diff --git a/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java b/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java index c45fb575270..6c2e1e2b2ce 100644 --- a/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java +++ b/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java @@ -39,10 +39,9 @@ public class BracketLegalityLabel extends LegalityLabel { private static final Logger logger = Logger.getLogger(BracketLegalityLabel.class); private static final String GROUP_GAME_CHANGES = "Game Changers"; - private static final String GROUP_INFINITE_COMBOS = "Infinite Combos"; + private static final String GROUP_INFINITE_COMBOS = "Early-game 2-Card Combos"; private static final String GROUP_MASS_LAND_DESTRUCTION = "Mass Land Destruction"; private static final String GROUP_EXTRA_TURN = "Extra Turns"; - private static final String GROUP_TUTORS = "Tutors"; private static final Map> MAX_GROUP_LIMITS = new LinkedHashMap<>(); @@ -78,8 +77,6 @@ public class BracketLegalityLabel extends LegalityLabel { Arrays.asList(0, 0, 0, 0, 99, 99)); MAX_GROUP_LIMITS.put(GROUP_EXTRA_TURN, Arrays.asList(0, 0, 0, 3, 99, 99)); - MAX_GROUP_LIMITS.put(GROUP_TUTORS, - Arrays.asList(0, 3, 3, 99, 99, 99)); } private static final String RESOURCE_INFINITE_COMBOS = "brackets/infinite-combos.txt"; @@ -92,7 +89,6 @@ public class BracketLegalityLabel extends LegalityLabel { private final List foundInfiniteCombos = new ArrayList<>(); private final List foundMassLandDestruction = new ArrayList<>(); private final List foundExtraTurn = new ArrayList<>(); - private final List foundTutors = new ArrayList<>(); private final List badCards = new ArrayList<>(); private final List fullGameChanges = new ArrayList<>(); @@ -126,9 +122,6 @@ public class BracketLegalityLabel extends LegalityLabel { if (this.foundExtraTurn.size() > getMaxCardsLimit(GROUP_EXTRA_TURN)) { this.badCards.addAll(this.foundExtraTurn); } - if (this.foundTutors.size() > getMaxCardsLimit(GROUP_TUTORS)) { - this.badCards.addAll(this.foundTutors); - } } private Integer getMaxCardsLimit(String groupName) { @@ -165,7 +158,6 @@ public class BracketLegalityLabel extends LegalityLabel { groups.put(GROUP_INFINITE_COMBOS + getStats(GROUP_INFINITE_COMBOS), this.foundInfiniteCombos); groups.put(GROUP_MASS_LAND_DESTRUCTION + getStats(GROUP_MASS_LAND_DESTRUCTION), this.foundMassLandDestruction); groups.put(GROUP_EXTRA_TURN + getStats(GROUP_EXTRA_TURN), this.foundExtraTurn); - groups.put(GROUP_TUTORS + getStats(GROUP_TUTORS), this.foundTutors); groups.forEach((group, cards) -> { showInfo.add("
"); showInfo.add("" + group + ""); @@ -199,9 +191,6 @@ public class BracketLegalityLabel extends LegalityLabel { case GROUP_EXTRA_TURN: currentAmount = this.foundExtraTurn.size(); break; - case GROUP_TUTORS: - currentAmount = this.foundTutors.size(); - break; default: throw new IllegalArgumentException("Unknown group " + groupName); } @@ -222,7 +211,6 @@ public class BracketLegalityLabel extends LegalityLabel { collectInfiniteCombos(deck); collectMassLandDestruction(deck); collectExtraTurn(deck); - collectTutors(deck); } private void collectGameChangers(Deck deck) { @@ -244,12 +232,9 @@ public class BracketLegalityLabel extends LegalityLabel { "Consecrated Sphinx", "Crop Rotation", "Cyclonic Rift", - "Deflecting Swat", "Enlightened Tutor", - "Expropriate", "Field of the Dead", "Fierce Guardianship", - "Food Chain", "Force of Will", "Gaea's Cradle", "Gamble", @@ -261,8 +246,6 @@ public class BracketLegalityLabel extends LegalityLabel { "Imperial Seal", "Intuition", "Jeska's Will", - "Jin-Gitaxias, Core Augur", - "Kinnan, Bonder Prodigy", "Lion's Eye Diamond", "Mana Vault", "Mishra's Workshop", @@ -280,18 +263,13 @@ public class BracketLegalityLabel extends LegalityLabel { "Serra's Sanctum", "Smothering Tithe", "Survival of the Fittest", - "Sway of the Stars", "Teferi's Protection", "Tergrid, God of Fright", "Thassa's Oracle", "The One Ring", "The Tabernacle at Pendrell Vale", "Underworld Breach", - "Urza, Lord High Artificer", "Vampiric Tutor", - "Vorinclex, Voice of Hunger", - "Yuriko, the Tiger's Shadow", - "Winota, Joiner of Forces", "Worldly Tutor" )); } @@ -393,19 +371,6 @@ public class BracketLegalityLabel extends LegalityLabel { .forEach(this.foundExtraTurn::add); } - private void collectTutors(Deck deck) { - // edh power level uses search for land and non-land card, but bracket need only non-land cards searching - this.foundTutors.clear(); - Stream.concat(deck.getCards().stream(), deck.getSideboard().stream()) - .filter(card -> card.getRules().stream() - .map(s -> s.toLowerCase(Locale.ENGLISH)) - .anyMatch(s -> s.contains("search your library") && !isTextContainsLandCard(s)) - ) - .map(Card::getName) - .sorted() - .forEach(this.foundTutors::add); - } - private boolean isTextContainsLandCard(String lowerText) { // TODO: share code with AbstractCommander and edh power level // TODO: add tests diff --git a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java index 4bd3166cbe9..59ad366a3f5 100644 --- a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java +++ b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java @@ -79,13 +79,15 @@ public enum MageTray { } catch (AWTException e) { log.error("TrayIcon could not be added: ", e); } - } catch (Exception e) { log.error(e); } } public synchronized void blink() { + if (trayIcon == null) + return; + if (state == 0) { synchronized (MageTray.class) { if (state == 0) { diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index e6bf6d18f40..771001da5c3 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -2115,6 +2115,9 @@ + + + @@ -2254,16 +2257,13 @@ - + - - - diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 85c9a155c22..13004ab13bf 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -2155,6 +2155,8 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); + txtBackgroundImagePath.setToolTipText("The selected image will be used as the background picture. Requires client restart to see changes."); + btnBrowseBackgroundImage.setText("Browse..."); btnBrowseBackgroundImage.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -2254,15 +2256,13 @@ public class PreferencesDialog extends javax.swing.JDialog { panelCardImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card images")); - cbUseDefaultImageFolder.setText("Use default location to save images"); + cbUseDefaultImageFolder.setText("Use default location to save card images"); cbUseDefaultImageFolder.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cbUseDefaultImageFolderActionPerformed(evt); } }); - txtImageFolderPath.setToolTipText("The selected image will be used as background picture. You have to restart MAGE to view a changed background image."); - btnBrowseImageLocation.setText("Browse..."); btnBrowseImageLocation.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 0cb2e6e4242..9030054dc6a 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -1700,7 +1700,7 @@ public class TablesPanel extends javax.swing.JPanel { MatchOptions options = new MatchOptions(gameName, gameType, multiPlayer); options.getPlayerTypes().add(PlayerType.HUMAN); options.getPlayerTypes().add(aiType); - for (int i=2 ; i < numPlayers ; i++) { + for (int i = 2; i < numPlayers; i++) { options.getPlayerTypes().add(aiType); } options.setDeckType("Variant Magic - Freeform Commander"); @@ -1719,9 +1719,9 @@ public class TablesPanel extends javax.swing.JPanel { table = SessionHandler.createTable(roomId, options); SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, testDeck, ""); - SessionHandler.joinTable(roomId, table.getTableId(), "Computer", aiType, 1, testDeck, ""); - for (int i=2 ; i < numPlayers ; i++) { - SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + i, aiType, 1, testDeck, ""); + SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + (multiPlayer ? " 2" : ""), aiType, 1, testDeck, ""); + for (int i = 2; i < numPlayers; i++) { + SessionHandler.joinTable(roomId, table.getTableId(), "Computer " + (i + 1), aiType, 1, testDeck, ""); } SessionHandler.startMatch(roomId, table.getTableId()); } catch (HeadlessException ex) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index 230c4e91ab7..2a26bbd9380 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -940,8 +940,13 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen private void setGameCardSides(CardView gameCard) { if (this.cardSideMain == null) { // new card - this.cardSideMain = gameCard; - this.cardSideOther = gameCard.getSecondCardFace(); + if (gameCard instanceof PermanentView) { + this.cardSideMain = gameCard; + this.cardSideOther = gameCard.isTransformed() ? ((PermanentView) gameCard).getOriginal() : gameCard.getSecondCardFace(); + } else { + this.cardSideMain = gameCard; + this.cardSideOther = gameCard.getSecondCardFace(); + } } else { // updated card if (this.cardSideMain.getName().equals(gameCard.getName())) { 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 5bc58deb879..96d4cf17590 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 @@ -611,10 +611,15 @@ public class ScryfallImageSupportCards { add("EOS"); // Edge of Eternities: Stellar Sights add("SPM"); // Marvel's Spider-Man add("SPE"); // Marvel's Spider-Man Eternal + add("LMAR"); // Marvel Legends Series Inserts add("MAR"); // Marvel Universe add("TLA"); // Avatar: The Last Airbender add("TLE"); // Avatar: The Last Airbender Eternal add("ECL"); // Lorwyn Eclipsed + add("TMT"); // Teenage Mutant Ninja Turtles + add("TMC"); // Teenage Mutant Ninja Turtles Eternal + add("MSH"); // Marvel Super Heroes + add("MSC"); // Marvel Super Heroes Commander // Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks add("CALC"); // Custom Alchemized versions of existing cards @@ -715,6 +720,7 @@ public class ScryfallImageSupportCards { put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back"); put("SLD/Steely Resolve/1326b", "https://api.scryfall.com/cards/sld/1326/en?format=image&face=back"); put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back"); + put("SLD/Teferi's Ageless Insight/2214b", "https://api.scryfall.com/cards/sld/2214/en?format=image&face=back"); put("SLD/Terror/750b", "https://api.scryfall.com/cards/sld/750/en?format=image&face=back"); put("SLD/Tuvasa the Sunlit/1328b", "https://api.scryfall.com/cards/sld/1328/en?format=image&face=back"); put("SLD/Ulamog, the Ceaseless Hunger/1122b", "https://api.scryfall.com/cards/sld/1122/en?format=image&face=back"); 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 f53f63eea97..7c3e4b0a507 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 @@ -1,10 +1,10 @@ package org.mage.plugins.card.dl.sources; +import mage.cards.repository.TokenRepository; + import java.util.HashMap; import java.util.Map; -import mage.cards.repository.TokenRepository; - /** * @author JayDi85 */ @@ -817,10 +817,13 @@ public class ScryfallImageSupportTokens { // SLD put("SLD/Angel", "https://api.scryfall.com/cards/sld/1340?format=image"); + put("SLD/Blood", "https://api.scryfall.com/cards/sld/2180?format=image"); put("SLD/Cat/1", "https://api.scryfall.com/cards/sld/1517?format=image"); put("SLD/Cat/2", "https://api.scryfall.com/cards/sld/27?format=image"); put("SLD/Cat/3", "https://api.scryfall.com/cards/sld/28?format=image"); put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image"); + put("SLD/Cordyceps Infected/1", "https://api.scryfall.com/cards/sld/2201?format=image"); + put("SLD/Cordyceps Infected/2", "https://api.scryfall.com/cards/sld/2206?format=image"); put("SLD/Dog", "https://api.scryfall.com/cards/sld/1516?format=image"); put("SLD/Egg", "https://api.scryfall.com/cards/sld/1398?format=image"); put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image"); @@ -2221,7 +2224,7 @@ public class ScryfallImageSupportTokens { put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?format=image"); put("WHO/Treasure/3", "https://api.scryfall.com/cards/twho/30?format=image"); put("WHO/Treasure/4", "https://api.scryfall.com/cards/twho/31?format=image"); - put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image"); + put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image"); // 8ED put("8ED/Bird", "https://api.scryfall.com/cards/p03/7/en?format=image"); @@ -2398,7 +2401,7 @@ public class ScryfallImageSupportTokens { put("OTP/Human Warrior", "https://api.scryfall.com/cards/totp/3/en?format=image"); put("OTP/Pest", "https://api.scryfall.com/cards/totp/4/en?format=image"); - // SCD + // SCD put("SCD/Beast", "https://api.scryfall.com/cards/tscd/19/en?format=image"); put("SCD/Bird", "https://api.scryfall.com/cards/tscd/2/en?format=image"); put("SCD/Cat", "https://api.scryfall.com/cards/tscd/3/en?format=image"); @@ -2546,6 +2549,7 @@ public class ScryfallImageSupportTokens { // DSK put("DSK/Beast", "https://api.scryfall.com/cards/tdsk/3?format=image"); + put("DSK/Demon", "https://api.scryfall.com/cards/tdsk/9?format=image"); put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image"); put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image"); put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image"); @@ -2558,6 +2562,7 @@ public class ScryfallImageSupportTokens { put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image"); put("DSK/Spirit/1", "https://api.scryfall.com/cards/tdsk/6?format=image"); put("DSK/Spirit/2", "https://api.scryfall.com/cards/tdsk/8?format=image"); + put("DSK/Toy", "https://api.scryfall.com/cards/tdsk/7?format=image"); put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image"); // DSC @@ -2738,7 +2743,7 @@ public class ScryfallImageSupportTokens { put("ACR/Treasure", "https://api.scryfall.com/cards/tacr/6?format=image"); // DD2 - put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image"); + put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image"); // FIN put("FIN/Hero/1", "https://api.scryfall.com/cards/tfin/2/en?format=image"); @@ -2826,6 +2831,35 @@ public class ScryfallImageSupportTokens { put("SPM/Spider", "https://api.scryfall.com/cards/tspm/3?format=image"); put("SPM/Treasure", "https://api.scryfall.com/cards/tspm/7?format=image"); + // TLA + put("TLA/Ally/1", "https://api.scryfall.com/cards/ttla/4/?format=image"); + put("TLA/Ally/2", "https://api.scryfall.com/cards/ttla/5/?format=image"); + put("TLA/Ally/3", "https://api.scryfall.com/cards/ttla/6/?format=image"); + put("TLA/Ally/4", "https://api.scryfall.com/cards/ttla/7/?format=image"); + put("TLA/Ally/5", "https://api.scryfall.com/cards/ttla/8/?format=image"); + put("TLA/Ballistic Boulder", "https://api.scryfall.com/cards/ttla/13/?format=image"); + put("TLA/Bear", "https://api.scryfall.com/cards/ttla/12/?format=image"); + put("TLA/Clue/1", "https://api.scryfall.com/cards/ttla/14/?format=image"); + put("TLA/Clue/2", "https://api.scryfall.com/cards/ttla/15/?format=image"); + put("TLA/Clue/3", "https://api.scryfall.com/cards/ttla/16/?format=image"); + put("TLA/Clue/4", "https://api.scryfall.com/cards/ttla/17/?format=image"); + put("TLA/Clue/5", "https://api.scryfall.com/cards/ttla/18/?format=image"); + put("TLA/Dragon", "https://api.scryfall.com/cards/ttla/9/?format=image"); + put("TLA/Food/1", "https://api.scryfall.com/cards/ttla/19/?format=image"); + put("TLA/Food/2", "https://api.scryfall.com/cards/ttla/20/?format=image"); + put("TLA/Food/3", "https://api.scryfall.com/cards/ttla/21/?format=image"); + put("TLA/Monk", "https://api.scryfall.com/cards/ttla/10/?format=image"); + put("TLA/Soldier", "https://api.scryfall.com/cards/ttla/11/?format=image"); + put("TLA/Spirit", "https://api.scryfall.com/cards/ttla/3/?format=image"); + put("TLA/Treasure", "https://api.scryfall.com/cards/ttla/22?format=image"); + + // TLE + put("TLE/Marit Lage", "https://api.scryfall.com/cards/ttle/1/?format=image"); + put("TLE/Soldier", "https://api.scryfall.com/cards/ttle/2?format=image"); + + // TMT + put("TMT/Mutagen", "https://api.scryfall.com/cards/ttmt/9?format=image"); + // JVC put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image"); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index 704395e0378..d81d5e797ae 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -558,12 +558,12 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements ); allCardsUrls.add(url); } - if (card.isModalDoubleFacedCard()) { - if (card.getModalDoubleFacedSecondSideName() == null || card.getModalDoubleFacedSecondSideName().trim().isEmpty()) { + if (card.isDoubleFacedCard()) { + if (card.getDoubleFacedSecondSideName() == null || card.getDoubleFacedSecondSideName().trim().isEmpty()) { throw new IllegalStateException("MDF card can't have empty name."); } CardDownloadData cardDownloadData = new CardDownloadData( - card.getModalDoubleFacedSecondSideName(), + card.getDoubleFacedSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), diff --git a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java index 34631c40516..dbcc8e01760 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/theme/ThemePluginImpl.java @@ -82,7 +82,7 @@ public class ThemePluginImpl implements ThemePlugin { } if (ui.containsKey("gamePanel") && ui.containsKey("jLayeredPane")) { - ImagePanel bgPanel = new ImagePanel(backgroundImage, ImagePanelStyle.TILED); + ImagePanel bgPanel = new ImagePanel(backgroundImage, ImagePanelStyle.COVER); // TODO: research - is all components used? And why it make transparent? unsetOpaque(ui.get("splitChatAndLogs")); diff --git a/Mage.Common/src/main/java/mage/components/ImagePanel.java b/Mage.Common/src/main/java/mage/components/ImagePanel.java index 0699e6d0cb4..dc1c317efb8 100644 --- a/Mage.Common/src/main/java/mage/components/ImagePanel.java +++ b/Mage.Common/src/main/java/mage/components/ImagePanel.java @@ -78,6 +78,9 @@ public class ImagePanel extends JPanel { case ACTUAL: drawActual(g); break; + case COVER: + drawCover(g); + break; } } @@ -99,4 +102,25 @@ public class ImagePanel extends JPanel { float y = (d.height - image.getHeight(null)) * alignmentY; g.drawImage(image, (int) x, (int) y, this); } + + private void drawCover(Graphics g) { + Dimension d = getSize(); + int imageWidth = image.getWidth(null); + int imageHeight = image.getHeight(null); + + // Calculate scale to cover the entire panel while maintaining aspect ratio + double scaleX = (double) d.width / imageWidth; + double scaleY = (double) d.height / imageHeight; + double scale = Math.max(scaleX, scaleY); + + // Calculate the scaled dimensions + int scaledWidth = (int) (imageWidth * scale); + int scaledHeight = (int) (imageHeight * scale); + + // Center the image + int x = (d.width - scaledWidth) / 2; + int y = (d.height - scaledHeight) / 2; + + g.drawImage(image, x, y, scaledWidth, scaledHeight, null); + } } diff --git a/Mage.Common/src/main/java/mage/components/ImagePanelStyle.java b/Mage.Common/src/main/java/mage/components/ImagePanelStyle.java index 01e1b4557bc..7e1a17839d1 100644 --- a/Mage.Common/src/main/java/mage/components/ImagePanelStyle.java +++ b/Mage.Common/src/main/java/mage/components/ImagePanelStyle.java @@ -4,5 +4,5 @@ package mage.components; * Created by IGOUDT on 7-3-2017. */ public enum ImagePanelStyle { - TILED, SCALED, ACTUAL + TILED, SCALED, ACTUAL, COVER } diff --git a/Mage.Common/src/main/java/mage/utils/SystemUtil.java b/Mage.Common/src/main/java/mage/utils/SystemUtil.java index c8144e49def..17124d7a084 100644 --- a/Mage.Common/src/main/java/mage/utils/SystemUtil.java +++ b/Mage.Common/src/main/java/mage/utils/SystemUtil.java @@ -601,14 +601,13 @@ public final class SystemUtil { continue; } - Optional playerOptional = findPlayer(game, command.player); - if (!playerOptional.isPresent()) { + Player player = findPlayer(game, command.player, feedbackPlayer); + if (player == null) { String mes = String.format("Unknown player: %s", line); errorsList.add(mes); logger.warn(mes); continue; } - Player player = playerOptional.get(); // SPECIAL token/emblem call (without SET name) if ("token".equalsIgnoreCase(command.zone)) { @@ -860,17 +859,54 @@ public final class SystemUtil { return false; } - /** - * Find player by name. - * - * @param game - * @param name - * @return - */ - private static Optional findPlayer(Game game, String name) { - return game.getPlayers().values().stream() - .filter(player -> player.getName().equals(name)).findFirst(); + private static Player findPlayer(Game game, String needName, Player feedbackPlayer) { + // real names + Player res = game.getPlayerList().stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(player -> player.getName().equals(needName)) + .findFirst() + .orElse(null); + // test names - cheat commands will be compatible in both modes (quick test and normal) + if (res == null) { + switch (needName.toLowerCase(Locale.ENGLISH)) { + case "me": + case "human": + case "human 1": + res = feedbackPlayer; + break; + case "opponent": + case "opponent 1": + case "computer": + case "computer 1": // multiplayer game uses Computer 2+ naming + case "ai": + case "ai 1": + // try AI + res = game.getPlayerList().stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(Player::isInGame) + .filter(Player::isComputer) + .findFirst() + .orElse(null); + if (res == null) { + // try opponent (human only games) + res = game.getOpponents(feedbackPlayer.getId(), true).stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .filter(Player::isInGame) + .findFirst() + .orElse(null); + } + break; + default: + // raise error message due unknown player name + break; + } + } + + return res; } public static String sanitize(String input) { diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 749488b8cf3..4892830edbb 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -27,11 +27,13 @@ import mage.counters.Counter; import mage.counters.CounterType; import mage.designations.Designation; import mage.filter.FilterMana; +import mage.game.ControllableOrOwnerable; import mage.game.Game; import mage.game.command.Dungeon; import mage.game.command.Emblem; import mage.game.command.Plane; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.game.stack.Spell; @@ -115,7 +117,7 @@ public class CardView extends SimpleCardView { protected List rightSplitRules; protected String rightSplitTypeLine; - protected boolean isModalDoubleFacedCard; + protected boolean isDoubleFacedCard; protected ArtRect artRect = ArtRect.NORMAL; @@ -237,7 +239,7 @@ public class CardView extends SimpleCardView { this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules); this.rightSplitTypeLine = cardView.rightSplitTypeLine; - this.isModalDoubleFacedCard = cardView.isModalDoubleFacedCard; + this.isDoubleFacedCard = cardView.isDoubleFacedCard; this.artRect = cardView.artRect; this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets); @@ -427,12 +429,18 @@ public class CardView extends SimpleCardView { this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols(); } else if (card instanceof ModalDoubleFacedCard) { - this.isModalDoubleFacedCard = true; - ModalDoubleFacedCard mainCard = ((ModalDoubleFacedCard) card); + this.isDoubleFacedCard = true; + DoubleFacedCard mainCard = ((DoubleFacedCard) card); fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); - } else if (card instanceof CardWithSpellOption) { + } else if (card instanceof TransformingDoubleFacedCard) { + this.isDoubleFacedCard = true; + DoubleFacedCard mainCard = ((DoubleFacedCard) card); + fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); + this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); + this.manaCostRightStr = new ArrayList<>(); + } else if (card instanceof CardWithSpellOption) { this.isSplitCard = true; CardWithSpellOption mainCard = ((CardWithSpellOption) card); leftSplitName = mainCard.getName(); @@ -530,13 +538,21 @@ public class CardView extends SimpleCardView { this.extraDeckCard = card.isExtraDeckCard(); + // TODO: can probably remove this after tdfc rework // transformable, double faces cards - this.transformable = card.isTransformable(); + if (!(sourceCard.getMainCard() instanceof DoubleFacedCard)) { + this.transformable = card.isTransformable(); - Card secondSideCard = card.getSecondCardFace(); - if (secondSideCard != null) { + Card secondSideCard = card.getSecondCardFace(); + if (secondSideCard != null) { + this.secondCardFace = new CardView(secondSideCard, game); + this.alternateName = secondCardFace.getName(); + } + } else if (card instanceof PermanentCard && card.isTransformable()) { + this.transformable = card.isTransformable(); + Card secondSideCard = (Card) ((PermanentCard) card).getOtherFace(); this.secondCardFace = new CardView(secondSideCard, game); - this.alternateName = secondCardFace.getName(); + this.alternateName = secondSideCard.getName(); } this.flipCard = card.isFlipCard(); @@ -544,11 +560,11 @@ public class CardView extends SimpleCardView { this.alternateName = card.getFlipCardName(); } - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { this.transformable = true; // enable GUI day/night button - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card; - this.secondCardFace = new CardView(mdfCard.getRightHalfCard(), game); - this.alternateName = mdfCard.getRightHalfCard().getName(); + DoubleFacedCard doubleFacedCard = (DoubleFacedCard) card; + this.secondCardFace = new CardView(doubleFacedCard.getRightHalfCard(), game); + this.alternateName = doubleFacedCard.getRightHalfCard().getName(); } Card meldsToCard = card.getMeldsToCard(); @@ -764,7 +780,11 @@ public class CardView extends SimpleCardView { String info; MageObject targetObject = game.getObject(t); if (targetObject != null) { - info = targetObject.getIdName(); + Player player = null; + if (targetObject instanceof ControllableOrOwnerable) { + player = game.getPlayer(((ControllableOrOwnerable) targetObject).getControllerOrOwnerId()); + } + info = (player == null ? "" : player.getName() + ": ") + targetObject.getIdName(); } else { Player targetPlayer = game.getPlayer(t); if (targetPlayer != null) { 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 index b90b5150ad1..e6b93fb521d 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -27,8 +27,7 @@ public abstract class AbstractCommander extends Constructed { private static List validators = Arrays.asList( PartnerValidator.instance, - PartnerSurvivorsValidator.instance, - PartnerFatherAndSonValidator.instance, + PartnerVariantValidator.instance, FriendsForeverValidator.instance, PartnerWithValidator.instance, ChooseABackgroundValidator.instance, 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 cc4e1c45827..e86103dafc9 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 @@ -44,7 +44,6 @@ public class DuelCommander extends Commander { banned.add("Library of Alexandria"); banned.add("Lion's Eye Diamond"); banned.add("Lotus Petal"); - banned.add("Loyal Retainers"); banned.add("Lutri, the Spellchaser"); banned.add("Maddening Hex"); banned.add("Mana Crypt"); @@ -93,8 +92,6 @@ public class DuelCommander extends Commander { bannedCommander.add("Ajani, Nacatl Pariah"); bannedCommander.add("Arahbo, Roar of the World"); - bannedCommander.add("Asmoranomardicadaistinaculdacar"); - bannedCommander.add("Baral, Chief of Compliance"); bannedCommander.add("Breya, Etherium Shaper"); bannedCommander.add("Derevi, Empyrial Tactician"); bannedCommander.add("Dihada, Binder of Wills"); @@ -102,7 +99,6 @@ public class DuelCommander extends Commander { bannedCommander.add("Edric, Spymaster of Trest"); bannedCommander.add("Emry, Lurker of the Loch"); bannedCommander.add("Eris, Roar of the Storm"); - bannedCommander.add("Esior, Wardwing Familiar"); bannedCommander.add("Ezio Auditore da Firenze"); bannedCommander.add("Geist of Saint Traft"); bannedCommander.add("Inalla, Archmage Ritualist"); @@ -116,7 +112,6 @@ public class DuelCommander extends Commander { bannedCommander.add("Omnath, Locus of Creation"); bannedCommander.add("Prime Speaker Vannifar"); bannedCommander.add("Raffine, Scheming Seer"); - bannedCommander.add("Rofellos, Llanowar Emissary"); bannedCommander.add("Shorikai, Genesis Engine"); bannedCommander.add("Tamiyo, Inquisitive Student"); bannedCommander.add("Tasigur, the Golden Fang"); 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 a75071e26b9..a1df921d081 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 @@ -32,6 +32,7 @@ public class Legacy extends Constructed { banned.add("Dig Through Time"); banned.add("Dreadhorde Arcanist"); banned.add("Earthcraft"); + banned.add("Entomb"); banned.add("Fastbond"); banned.add("Flash"); banned.add("Frantic Search"); @@ -56,6 +57,7 @@ public class Legacy extends Constructed { banned.add("Mox Ruby"); banned.add("Mox Sapphire"); banned.add("Mystical Tutor"); + banned.add("Nadu, Winged Wisdom"); banned.add("Necropotence"); banned.add("Oath of Druids"); banned.add("Oko, Thief of Crowns"); 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 6dbba75643f..b4c431c6642 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 @@ -46,6 +46,7 @@ public class Pauper extends Constructed { banned.add("Gitaxian Probe"); banned.add("Grapeshot"); banned.add("Gush"); + banned.add("High Tide"); banned.add("Hymn to Tourach"); banned.add("Invigorate"); banned.add("Kuldotha Rebirth"); 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 4d86075f3ee..22cf8af5c0f 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 @@ -30,6 +30,7 @@ public class Pioneer extends Constructed { banned.add("Field of the Dead"); banned.add("Flooded Strand"); banned.add("Geological Appraiser"); + banned.add("Heartfire Hero"); banned.add("Inverter of Truth"); banned.add("Jegantha, the Wellspring"); banned.add("Karn, the Great Creator"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java index 0796aaf056d..b1973ae9f0b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java @@ -24,8 +24,11 @@ public class Standard extends Constructed { banned.add("Heartfire Hero"); banned.add("Hopeless Nightmare"); banned.add("Monstrous Rage"); + banned.add("Proft's Eidetic Memory"); + banned.add("Screaming Nemesis"); banned.add("This Town Ain't Big Enough"); banned.add("Up the Beanstalk"); + banned.add("Vivi Ornitier"); } static List makeLegalSets() { 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 aaaa45006e8..c2c364d9cb5 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 @@ -206,9 +206,9 @@ public class TinyLeaders extends Constructed { if (card instanceof SplitCard) { costs.add(((SplitCard) card).getLeftHalfCard().getManaValue()); costs.add(((SplitCard) card).getRightHalfCard().getManaValue()); - } else if (card instanceof ModalDoubleFacedCard) { - costs.add(((ModalDoubleFacedCard) card).getLeftHalfCard().getManaValue()); - costs.add(((ModalDoubleFacedCard) card).getRightHalfCard().getManaValue()); + } else if (card instanceof DoubleFacedCard) { + costs.add(((DoubleFacedCard) card).getLeftHalfCard().getManaValue()); + costs.add(((DoubleFacedCard) card).getRightHalfCard().getManaValue()); } else { costs.add(card.getManaValue()); } diff --git a/Mage.Sets/src/mage/cards/a/AangALotToLearn.java b/Mage.Sets/src/mage/cards/a/AangALotToLearn.java new file mode 100644 index 00000000000..348834371d5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AangALotToLearn.java @@ -0,0 +1,58 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AangALotToLearn extends CardImpl { + + public AangALotToLearn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G/W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.AVATAR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Aang has vigilance as long as there's a Lesson card in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield), + LessonsInGraveCondition.ONE, "{this} has vigilance as long as there's a Lesson card in your graveyard" + )).addHint(LessonsInGraveCondition.getHint())); + + // Whenever another creature you control dies, put a +1/+1 counter on Aang. + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL + )); + } + + private AangALotToLearn(final AangALotToLearn card) { + super(card); + } + + @Override + public AangALotToLearn copy() { + return new AangALotToLearn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AangAndKatara.java b/Mage.Sets/src/mage/cards/a/AangAndKatara.java new file mode 100644 index 00000000000..6b2c1c3f7c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AangAndKatara.java @@ -0,0 +1,64 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +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.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AangAndKatara extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("tapped artifacts and/or creatures you control"); + + static { + filter.add(TappedPredicate.TAPPED); + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, null); + private static final Hint hint = new ValueHint("Tapped artifacts and creatures you control", xValue); + + public AangAndKatara(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.AVATAR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Whenever Aang and Katara enter or attack, create X 1/1 white Ally creature tokens, where X is the number of tapped artifacts and/or creatures you control. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateTokenEffect(new AllyToken(), xValue)) + .setTriggerPhrase("Whenever {this} enter or attack, ").addHint(hint)); + } + + private AangAndKatara(final AangAndKatara card) { + super(card); + } + + @Override + public AangAndKatara copy() { + return new AangAndKatara(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java b/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java new file mode 100644 index 00000000000..d77dd1f2fc4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AangAtTheCrossroads.java @@ -0,0 +1,89 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AangAtTheCrossroads extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 4 or less"); + private static final FilterPermanent saviorFilter = new FilterPermanent("land creatures"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5)); + saviorFilter.add(CardType.LAND.getPredicate()); + saviorFilter.add(CardType.CREATURE.getPredicate()); + } + + public AangAtTheCrossroads(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{2}{G}{W}{U}", + "Aang, Destined Savior", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, ""); + + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); + + // When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM + ))); + + // When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep. + this.getLeftHalfCard().addAbility(new LeavesBattlefieldAllTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect()) + ).setText("transform {this} at the beginning of the next upkeep"), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL) + .setTriggerPhrase("When another creature you control leaves the battlefield, ")); + + // Aang, Destined Savior + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Land creatures you control have vigilance. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, saviorFilter + ))); + + // At the beginning of combat on your turn, earthbend 2. + Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(2)); + ability.addTarget(new TargetControlledLandPermanent()); + this.getRightHalfCard().addAbility(ability); + } + + private AangAtTheCrossroads(final AangAtTheCrossroads card) { + super(card); + } + + @Override + public AangAtTheCrossroads copy() { + return new AangAtTheCrossroads(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java b/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java deleted file mode 100644 index 951e3c91215..00000000000 --- a/Mage.Sets/src/mage/cards/a/AangMasterOfElements.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.constants.TargetController; -import mage.counters.CounterType; -import mage.filter.FilterCard; -import mage.game.Game; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AangMasterOfElements extends CardImpl { - - private static final FilterCard filter = new FilterCard("spells"); - - public AangMasterOfElements(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Spells you cast cost {W}{U}{B}{R}{G} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( - filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true - ))); - - // At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.ANY, - new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost()) - .addEffect(new DrawCardSourceControllerEffect(4).concatBy(",")) - .addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)) - .setText(", put four +1/+1 counters on him")) - .addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT) - .setText(", and he deals 4 damage to each opponent")), - false - )); - } - - private AangMasterOfElements(final AangMasterOfElements card) { - super(card); - } - - @Override - public AangMasterOfElements copy() { - return new AangMasterOfElements(this); - } -} - -class AangMasterOfElementsCost extends CostImpl { - - AangMasterOfElementsCost() { - super(); - text = "transform {this}"; - } - - private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) { - super(cost); - } - - @Override - public AangMasterOfElementsCost copy() { - return new AangMasterOfElementsCost(this); - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return Optional - .ofNullable(source.getSourcePermanentIfItStillExists(game)) - .filter(Card::isTransformable) - .isPresent(); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - paid = Optional - .ofNullable(source.getSourcePermanentIfItStillExists(game)) - .filter(permanent -> permanent.transform(source, game)) - .isPresent(); - return paid; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java b/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java new file mode 100644 index 00000000000..cf199e538c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AangSwiftSavior.java @@ -0,0 +1,89 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterSpellOrPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetSpellOrPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AangSwiftSavior extends TransformingDoubleFacedCard { + + private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("other target creature or spell"); + private static final FilterPermanent laFilter = new FilterControlledCreaturePermanent("tapped creature you control"); + + static { + } + static { + filter.getPermanentFilter().add(CardType.CREATURE.getPredicate()); + filter.getPermanentFilter().add(AnotherPredicate.instance); + laFilter.add(TappedPredicate.TAPPED); + } + + public AangSwiftSavior(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{1}{W}{U}", + "Aang and La, Ocean's Fury", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.SPIRIT, SubType.ALLY}, ""); + + this.getLeftHalfCard().setPT(2, 3); + this.getRightHalfCard().setPT(5, 5); + + // Flash + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); + + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); + + // When Aang enters, airbend up to one other target creature or spell. + Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect()); + ability.addTarget(new TargetSpellOrPermanent(0, 1, filter, false)); + this.getLeftHalfCard().addAbility(ability); + + // Waterbend {8}: Transform Aang. + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new WaterbendCost(8))); + + // Aang and La, Ocean's Fury + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), laFilter)).setTriggerPhrase("Whenever {this} attack, ")); + } + + private AangSwiftSavior(final AangSwiftSavior card) { + super(card); + } + + @Override + public AangSwiftSavior copy() { + return new AangSwiftSavior(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AbandonedAirTemple.java b/Mage.Sets/src/mage/cards/a/AbandonedAirTemple.java new file mode 100644 index 00000000000..118806cf04a --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AbandonedAirTemple.java @@ -0,0 +1,50 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.YouControlABasicLandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AbandonedAirTemple extends CardImpl { + + public AbandonedAirTemple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a basic land. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance) + .addHint(YouControlABasicLandCondition.getHint())); + + // {T}: Add {W}. + this.addAbility(new WhiteManaAbility()); + + // {3}{W}, {T}: Put a +1/+1 counter on each creature you control. + Ability ability = new SimpleActivatedAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ), new ManaCostsImpl<>("{3}{W}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private AbandonedAirTemple(final AbandonedAirTemple card) { + super(card); + } + + @Override + public AbandonedAirTemple copy() { + return new AbandonedAirTemple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java b/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java index 768d6508925..8aac503b87c 100644 --- a/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java +++ b/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java @@ -6,10 +6,10 @@ import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.EntersBattlefieldUnderControlOfOpponentOfChoiceEffect; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.PartnerVariantType; import mage.constants.SubType; import mage.constants.SuperType; import mage.game.permanent.token.CordycepsInfectedToken; @@ -41,7 +41,7 @@ public final class AbbyMercilessSoldier extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect())); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private AbbyMercilessSoldier(final AbbyMercilessSoldier card) { diff --git a/Mage.Sets/src/mage/cards/a/AberrantResearcher.java b/Mage.Sets/src/mage/cards/a/AberrantResearcher.java index 69e5b58f690..db75f8ba478 100644 --- a/Mage.Sets/src/mage/cards/a/AberrantResearcher.java +++ b/Mage.Sets/src/mage/cards/a/AberrantResearcher.java @@ -1,16 +1,16 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.players.Player; @@ -19,23 +19,26 @@ import java.util.UUID; /** * @author fireshoes */ -public final class AberrantResearcher extends CardImpl { +public final class AberrantResearcher extends TransformingDoubleFacedCard { public AberrantResearcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.INSECT); - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.INSECT}, "{3}{U}", + "Perfected Form", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT, SubType.HORROR}, "U"); - this.secondSideCardClazz = mage.cards.p.PerfectedForm.class; + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(5, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // At the beginning of your upkeep, put the top card of your library into your graveyard. If it's an instant or sorcery card, transform Aberrant Researcher. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect())); + + // Perfected Form + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private AberrantResearcher(final AberrantResearcher card) { diff --git a/Mage.Sets/src/mage/cards/a/AbolisherOfBloodlines.java b/Mage.Sets/src/mage/cards/a/AbolisherOfBloodlines.java deleted file mode 100644 index 1cde0a968c6..00000000000 --- a/Mage.Sets/src/mage/cards/a/AbolisherOfBloodlines.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.SacrificeEffect; -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 mage.target.common.TargetOpponent; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class AbolisherOfBloodlines extends CardImpl { - - public AbolisherOfBloodlines(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When this creature transforms into Abolisher of Bloodlines, target opponent sacrifices three creatures. - Ability ability = new TransformIntoSourceTriggeredAbility(new SacrificeEffect( - StaticFilters.FILTER_PERMANENT_CREATURES, 3, "target opponent" - )); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private AbolisherOfBloodlines(final AbolisherOfBloodlines card) { - super(card); - } - - @Override - public AbolisherOfBloodlines copy() { - return new AbolisherOfBloodlines(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AccumulateWisdom.java b/Mage.Sets/src/mage/cards/a/AccumulateWisdom.java new file mode 100644 index 00000000000..d0e1e859fcb --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AccumulateWisdom.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AccumulateWisdom extends CardImpl { + + public AccumulateWisdom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + this.subtype.add(SubType.LESSON); + + // Look at the top three cards of your library. Put one of those cards into your hand and the rest on the bottom of your library in any order. Put each of those cards into your hand instead if there are three or more Lesson cards in your graveyard. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new LookLibraryAndPickControllerEffect(3, 3, PutCards.HAND, PutCards.BOTTOM_ANY), + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY), + LessonsInGraveCondition.THREE, "look at the top three cards of your library. " + + "Put one of those cards into your hand and the rest on the bottom of your library in any order. " + + "Put each of those cards into your hand instead if there are three or more Lesson cards in your graveyard" + )); + this.getSpellAbility().addHint(LessonsInGraveCondition.getHint()); + } + + private AccumulateWisdom(final AccumulateWisdom card) { + super(card); + } + + @Override + public AccumulateWisdom copy() { + return new AccumulateWisdom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AccursedWitch.java b/Mage.Sets/src/mage/cards/a/AccursedWitch.java index c214b37dd02..b2f2f329017 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedWitch.java +++ b/Mage.Sets/src/mage/cards/a/AccursedWitch.java @@ -1,49 +1,76 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; -import mage.cards.Card; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.DoubleFacedCardHalf; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; import mage.players.Player; +import mage.target.TargetPlayer; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** * @author halljared */ -public final class AccursedWitch extends CardImpl { +public final class AccursedWitch extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCard("spells"); public AccursedWitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.i.InfectiousCurse.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "{3}{B}", + "Infectious Curse", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "B"); + this.getLeftHalfCard().setPT(4, 2); // Spells your opponents cast that target Accursed Witch cost {1} less to cast. - this.addAbility(new SimpleStaticAbility( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( new SpellsCostModificationThatTargetSourceEffect(-1, filter, TargetController.OPPONENT)) ); // When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent. - this.addAbility(new TransformAbility()); Ability ability = new DiesSourceTriggeredAbility(new AccursedWitchReturnTransformedEffect()); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Infectious Curse + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.Damage)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Spells you cast that target enchanted player cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new InfectiousCurseCostReductionEffect())); + + // At the beginning of enchanted player's upkeep, that player loses 1 life and you gain 1 life. + Ability upkeepAbility = new BeginningOfUpkeepTriggeredAbility( + TargetController.ENCHANTED, new LoseLifeTargetEffect(1).setText("that player loses 1 life"), + false + ); + upkeepAbility.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(upkeepAbility); } private AccursedWitch(final AccursedWitch card) { @@ -80,16 +107,67 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect { return false; } - Card card = game.getCard(source.getSourceId()); + DoubleFacedCardHalf card = (DoubleFacedCardHalf) game.getCard(source.getSourceId()); if (card == null) { return false; } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - game.getState().setValue("attachTo:" + source.getSourceId(), attachTo.getId()); + game.getState().setValue("attachTo:" + card.getOtherSide().getId(), attachTo.getId()); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - attachTo.addAttachment(card.getId(), source, game); + attachTo.addAttachment(card.getOtherSide().getId(), source, game); } return true; } } +class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl { + + InfectiousCurseCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + this.staticText = "Spells you cast that target enchanted player cost {1} less to cast"; + } + + private InfectiousCurseCostReductionEffect(InfectiousCurseCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, 1); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (!(abilityToModify instanceof SpellAbility)) { + return false; + } + + if (!source.isControlledBy(abilityToModify.getControllerId())) { + return false; + } + + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment == null || enchantment.getAttachedTo() == null) { + return false; + } + + Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); + Set allTargets; + if (spell != null) { + // real cast + allTargets = CardUtil.getAllSelectedTargets(abilityToModify, game); + } else { + // playable + allTargets = CardUtil.getAllPossibleTargets(abilityToModify, game); + } + + // try to reduce all the time (if it possible to target) + return allTargets.stream().anyMatch(target -> Objects.equals(target, enchantment.getAttachedTo())); + } + + @Override + public InfectiousCurseCostReductionEffect copy() { + return new InfectiousCurseCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java b/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java index 06c22233f9f..3ffb59c98fc 100644 --- a/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java +++ b/Mage.Sets/src/mage/cards/a/AclazotzDeepestBetrayal.java @@ -1,16 +1,23 @@ package mage.cards.a; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.BlackManaAbility; import mage.cards.*; import mage.constants.*; import mage.filter.StaticFilters; @@ -28,33 +35,43 @@ import java.util.UUID; /** * @author Susucr */ -public final class AclazotzDeepestBetrayal extends CardImpl { +public final class AclazotzDeepestBetrayal extends TransformingDoubleFacedCard { + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY); + private static final Hint hint = new ConditionHint(condition); public AclazotzDeepestBetrayal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); - this.secondSideCardClazz = mage.cards.t.TempleOfTheDead.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BAT, SubType.GOD}, "{3}{B}{B}", + "Temple of the Dead", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.BAT); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + this.getLeftHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Whenever Aclazotz attacks, each opponent discards a card. For each opponent who can't, you draw a card. - this.addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect())); // Whenever an opponent discards a land card, create a 1/1 black Bat creature token with flying. - this.addAbility(new AclazotzDeepestBetrayalTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AclazotzDeepestBetrayalTriggeredAbility()); // When Aclazotz dies, return it to the battlefield tapped and transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect())); + + // Temple of the Dead + // {T}: Add {B}. + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery. + Ability ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability.addHint(hint)); } private AclazotzDeepestBetrayal(final AclazotzDeepestBetrayal card) { diff --git a/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java b/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java index 2fc675be257..8e0489ff96a 100644 --- a/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java +++ b/Mage.Sets/src/mage/cards/a/AcolyteOfTheInferno.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -28,7 +27,9 @@ public final class AcolyteOfTheInferno extends CardImpl { this.addAbility(new RenownAbility(1)); // Whenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(2, true, "that creature", "it"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility( + new DamageTargetEffect(2, "it") + .withTargetDescription("that creature"), false)); } private AcolyteOfTheInferno(final AcolyteOfTheInferno card) { diff --git a/Mage.Sets/src/mage/cards/a/AcolytesReward.java b/Mage.Sets/src/mage/cards/a/AcolytesReward.java index 130c6da7ec8..2767bc017a3 100644 --- a/Mage.Sets/src/mage/cards/a/AcolytesReward.java +++ b/Mage.Sets/src/mage/cards/a/AcolytesReward.java @@ -2,16 +2,14 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.DevotionCount; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; @@ -46,16 +44,14 @@ public final class AcolytesReward extends CardImpl { class AcolytesRewardEffect extends PreventionEffectImpl { - protected int amount = 0; AcolytesRewardEffect() { - super(Duration.EndOfTurn); + super(Duration.EndOfTurn, 0, false, true, DevotionCount.W); staticText = "Prevent the next X damage that would be dealt to target creature this turn, where X is your devotion to white. If damage is prevented this way, {this} deals that much damage to any target"; } private AcolytesRewardEffect(final AcolytesRewardEffect effect) { super(effect); - this.amount = effect.amount; } @Override @@ -63,64 +59,25 @@ class AcolytesRewardEffect extends PreventionEffectImpl { return new AcolytesRewardEffect(this); } - @Override - public void init(Ability source, Game game) { - super.init(source, game); - amount = DevotionCount.W.calculate(game, source, this); - } - @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - boolean result = false; - int toPrevent = amount; - if (event.getAmount() < this.amount) { - toPrevent = event.getAmount(); - amount -= event.getAmount(); - } else { - amount = 0; + PreventionEffectData preventionData = preventDamageAction(event, source, game); + if (preventionData.getPreventedDamage() > 0) { + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature != null) { + targetCreature.damage(preventionData.getPreventedDamage(), source.getSourceId(), source, game, false, true); + } + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetCreature != null) { + targetPlayer.damage(preventionData.getPreventedDamage(), source.getSourceId(), source, game, false, true); + } } - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent, ((DamageEvent) event).isCombatDamage()); - if (game.replaceEvent(preventEvent)) { - return result; - } - Permanent targetCreature = game.getPermanent(event.getTargetId()); - if (targetCreature == null) { - return result; - } - if (amount == 0) { - this.used = true; - this.discard(); - } - if (event.getAmount() >= toPrevent) { - event.setAmount(event.getAmount() - toPrevent); - } else { - event.setAmount(0); - result = true; - } - if (toPrevent == 0) { - return result; - } - game.informPlayers("Acolyte's Reward prevented " + toPrevent + " to " + targetCreature.getName()); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent)); - - Player targetPlayer = game.getPlayer(source.getTargets().get(1).getFirstTarget()); - if (targetPlayer != null) { - targetPlayer.damage(toPrevent, source.getSourceId(), source, game); - game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetPlayer.getLogName()); - return result; - } - Permanent targetDamageCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (targetDamageCreature == null) { - return result; - } - targetDamageCreature.damage(toPrevent, source.getSourceId(), source, game, false, true); - game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetDamageCreature.getName()); - return result; + return false; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - return !this.used && super.applies(event, source, game) && event.getTargetId().equals(source.getFirstTarget()); + return super.applies(event, source, game) && event.getTargetId().equals(source.getFirstTarget()); } } diff --git a/Mage.Sets/src/mage/cards/a/AdantoTheFirstFort.java b/Mage.Sets/src/mage/cards/a/AdantoTheFirstFort.java deleted file mode 100644 index 287da954970..00000000000 --- a/Mage.Sets/src/mage/cards/a/AdantoTheFirstFort.java +++ /dev/null @@ -1,48 +0,0 @@ - -package mage.cards.a; - -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.CreateTokenEffect; -import mage.abilities.mana.WhiteManaAbility; -import mage.constants.SuperType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.permanent.token.IxalanVampireToken; - -/** - * - * @author TheElk801 - */ -public final class AdantoTheFirstFort extends CardImpl { - - public AdantoTheFirstFort(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // T: Add W. - this.addAbility(new WhiteManaAbility()); - - // 2W, T: Create a 1/1 white Vampire creature token with lifelink. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new IxalanVampireToken()), new ManaCostsImpl<>("{2}{W}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private AdantoTheFirstFort(final AdantoTheFirstFort card) { - super(card); - } - - @Override - public AdantoTheFirstFort copy() { - return new AdantoTheFirstFort(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java b/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java index 2eed3297193..5126774a212 100644 --- a/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java +++ b/Mage.Sets/src/mage/cards/a/AdrenalineJockey.java @@ -41,7 +41,7 @@ public final class AdrenalineJockey extends CardImpl { // Whenever a player casts a spell, if it's not their turn, this creature deals 4 damage to them. this.addAbility(new SpellCastAllTriggeredAbility( - new DamageTargetEffect(4, true, "them"), + new DamageTargetEffect(4).withTargetDescription("them"), filter, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/a/AerithRescueMission.java b/Mage.Sets/src/mage/cards/a/AerithRescueMission.java index f63fd779d57..f71e88023bc 100644 --- a/Mage.Sets/src/mage/cards/a/AerithRescueMission.java +++ b/Mage.Sets/src/mage/cards/a/AerithRescueMission.java @@ -1,17 +1,28 @@ package mage.cards.a; +import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; 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.predicate.permanent.PermanentReferenceInCollectionPredicate; +import mage.game.Game; import mage.game.permanent.token.HeroToken; +import mage.target.Target; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 @@ -28,8 +39,7 @@ public final class AerithRescueMission extends CardImpl { // * Take 59 Flights of Stairs -- Tap up to three target creatures. Put a stun counter on one of them. this.getSpellAbility().addMode(new Mode(new TapTargetEffect()) - .addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) - .setText("Put a stun counter on one of them")) + .addEffect(new AerithRescueMissionStunEffect()) .addTarget(new TargetCreaturePermanent(0, 3)) .withFlavorWord("Take 59 Flights of Stairs")); } @@ -43,3 +53,34 @@ public final class AerithRescueMission extends CardImpl { return new AerithRescueMission(this); } } + +class AerithRescueMissionStunEffect extends OneShotEffect { + + AerithRescueMissionStunEffect() { + super(Outcome.Detriment); + staticText = "Put a stun counter on one of them"; + } + + private AerithRescueMissionStunEffect(final AerithRescueMissionStunEffect effect) { + super(effect); + } + + @Override + public AerithRescueMissionStunEffect copy() { + return new AerithRescueMissionStunEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent filter = new FilterPermanent("creature to put a stun counter on"); + filter.add(new PermanentReferenceInCollectionPredicate(this.getTargetPointer().getTargets(game, source).stream() + .map(game::getPermanent).collect(Collectors.toList()), game)); + Target target = new TargetPermanent(filter).withNotTarget(true); + if (target.choose(Outcome.UnboostCreature, source.getControllerId(), source, game)) { + Effect eff = new AddCountersTargetEffect(CounterType.STUN.createInstance()); + eff.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); + return eff.apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java b/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java index 8df4502e60a..bc7cd55d194 100644 --- a/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java +++ b/Mage.Sets/src/mage/cards/a/AetherbladeAgent.java @@ -1,13 +1,13 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -16,23 +16,28 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AetherbladeAgent extends CardImpl { +public final class AetherbladeAgent extends TransformingDoubleFacedCard { public AetherbladeAgent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.g.GitaxianMindstinger.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{B}", + "Gitaxian Mindstinger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ROGUE}, "UB"); + this.getLeftHalfCard().setPT(1, 1); + this.getRightHalfCard().setPT(3, 3); // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); + this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance()); // {4}{U/P}: Transform Aetherblade Agent. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}"))); + + // Gitaxian Mindstinger + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Gitaxian Mindstinger deals combat damage to a player or battle, draw a card. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility(new DrawCardSourceControllerEffect(1),false)); } private AetherbladeAgent(final AetherbladeAgent card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherwingGoldenScaleFlagship.java b/Mage.Sets/src/mage/cards/a/AetherwingGoldenScaleFlagship.java deleted file mode 100644 index 2edb57f2800..00000000000 --- a/Mage.Sets/src/mage/cards/a/AetherwingGoldenScaleFlagship.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; -import mage.abilities.keyword.CrewAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AetherwingGoldenScaleFlagship extends CardImpl { - - public AetherwingGoldenScaleFlagship(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Aetherwing, Golden-Scale Flagship's power is equal to the number of artifacts you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, - new SetBasePowerSourceEffect(ArtifactYouControlCount.instance) - .setText("{this}'s power is equal to the number of artifacts you control") - )); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private AetherwingGoldenScaleFlagship(final AetherwingGoldenScaleFlagship card) { - super(card); - } - - @Override - public AetherwingGoldenScaleFlagship copy() { - return new AetherwingGoldenScaleFlagship(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java b/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java index b5dc48b063c..00aba239c02 100644 --- a/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java +++ b/Mage.Sets/src/mage/cards/a/AfflictedDeserter.java @@ -1,33 +1,49 @@ package mage.cards.a; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetArtifactPermanent; +import java.util.Optional; import java.util.UUID; /** * @author BetaSteward */ -public final class AfflictedDeserter extends CardImpl { +public final class AfflictedDeserter extends TransformingDoubleFacedCard { public AfflictedDeserter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - - this.secondSideCardClazz = mage.cards.w.WerewolfRansacker.class; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Werewolf Ransacker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(5, 4); // At the beginning of each upkeep, if no spells were cast last turn, transform Afflicted Deserter. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Werewolf Ransacker + // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. + Ability ability = new TransformIntoSourceTriggeredAbility(new WerewolfRansackerEffect(), true, true); + ability.addTarget(new TargetArtifactPermanent()); + this.getRightHalfCard().addAbility(ability); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); + } private AfflictedDeserter(final AfflictedDeserter card) { @@ -39,3 +55,39 @@ public final class AfflictedDeserter extends CardImpl { return new AfflictedDeserter(this); } } + +class WerewolfRansackerEffect extends OneShotEffect { + + WerewolfRansackerEffect() { + super(Outcome.DestroyPermanent); + staticText = "destroy target artifact. If that artifact is put into a graveyard this way, " + + "{this} deals 3 damage to that artifact's controller"; + } + + private WerewolfRansackerEffect(final WerewolfRansackerEffect effect) { + super(effect); + } + + @Override + public WerewolfRansackerEffect copy() { + return new WerewolfRansackerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + permanent.destroy(source, game); + if (game.getState().getZone(permanent.getId()) != Zone.GRAVEYARD) { + return true; + } + Optional.of(permanent) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.damage(3, source, game)); + return true; + } +} + diff --git a/Mage.Sets/src/mage/cards/a/AgentVenom.java b/Mage.Sets/src/mage/cards/a/AgentVenom.java index 9217071f4a2..f18334918cb 100644 --- a/Mage.Sets/src/mage/cards/a/AgentVenom.java +++ b/Mage.Sets/src/mage/cards/a/AgentVenom.java @@ -45,7 +45,7 @@ public final class AgentVenom extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Menace - this.addAbility(new MenaceAbility()); + this.addAbility(new MenaceAbility(false)); // Whenever another nontoken creature you control dies, you draw a card and lose 1 life. Ability ability = new DiesCreatureTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/a/AgnaQela.java b/Mage.Sets/src/mage/cards/a/AgnaQela.java new file mode 100644 index 00000000000..2af54ef1ce0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AgnaQela.java @@ -0,0 +1,48 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.YouControlABasicLandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +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 AgnaQela extends CardImpl { + + public AgnaQela(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a basic land. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance) + .addHint(YouControlABasicLandCondition.getHint())); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // {2}{U}, {T}: Draw a card, then discard a card. + Ability ability = new SimpleActivatedAbility( + new DrawDiscardControllerEffect(1, 1), new ManaCostsImpl<>("{2}{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private AgnaQela(final AgnaQela card) { + super(card); + } + + @Override + public AgnaQela copy() { + return new AgnaQela(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AirNomadLegacy.java b/Mage.Sets/src/mage/cards/a/AirNomadLegacy.java new file mode 100644 index 00000000000..3ad0a54cfb3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirNomadLegacy.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.filter.StaticFilters; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AirNomadLegacy extends CardImpl { + + public AirNomadLegacy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{U}"); + + // When this enchantment enters, create a Clue token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + + // Creatures you control with flying get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURE_FLYING + ).setText("creatures you control with flying get +1/+1"))); + } + + private AirNomadLegacy(final AirNomadLegacy card) { + super(card); + } + + @Override + public AirNomadLegacy copy() { + return new AirNomadLegacy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AirNomadStudent.java b/Mage.Sets/src/mage/cards/a/AirNomadStudent.java new file mode 100644 index 00000000000..2174728a083 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirNomadStudent.java @@ -0,0 +1,51 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.AttackedThisTurnSourceCondition; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +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 AirNomadStudent extends CardImpl { + + private static final Condition condition = new InvertCondition( + AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn" + ); + + public AirNomadStudent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your end step, if this creature didn't attack this turn, put a +1/+1 counter on it. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it")).withInterveningIf(condition)); + } + + private AirNomadStudent(final AirNomadStudent card) { + super(card); + } + + @Override + public AirNomadStudent copy() { + return new AirNomadStudent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AirbenderAscension.java b/Mage.Sets/src/mage/cards/a/AirbenderAscension.java new file mode 100644 index 00000000000..cf862437492 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirbenderAscension.java @@ -0,0 +1,59 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.effects.common.ExileThenReturnTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AirbenderAscension extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4); + + public AirbenderAscension(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + // When this enchantment enters, airbend up to one target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect()); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // Whenever a creature you control enters, put a quest counter on this enchantment. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.QUEST.createInstance()), + StaticFilters.FILTER_CONTROLLED_CREATURE + )); + + // At the beginning of your end step, if this enchantment has four or more quest counters on it, exile up to one target creature you control, then return it to the battlefield under its owner's control. + ability = new BeginningOfEndStepTriggeredAbility( + new ExileThenReturnTargetEffect(false, false) + ).withInterveningIf(condition); + ability.addTarget(new TargetControlledCreaturePermanent(0, 1)); + this.addAbility(ability); + } + + private AirbenderAscension(final AirbenderAscension card) { + super(card); + } + + @Override + public AirbenderAscension copy() { + return new AirbenderAscension(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AirbendersReversal.java b/Mage.Sets/src/mage/cards/a/AirbendersReversal.java new file mode 100644 index 00000000000..4175a1b20b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirbendersReversal.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetAttackingCreature; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AirbendersReversal extends CardImpl { + + public AirbendersReversal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + this.subtype.add(SubType.LESSON); + + // Choose one -- + // * Destroy target attacking creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + + // * Airbend target creature you control. + this.getSpellAbility().addMode(new Mode(new AirbendTargetEffect()) + .addTarget(new TargetControlledCreaturePermanent())); + } + + private AirbendersReversal(final AirbendersReversal card) { + super(card); + } + + @Override + public AirbendersReversal copy() { + return new AirbendersReversal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AirshipEngineRoom.java b/Mage.Sets/src/mage/cards/a/AirshipEngineRoom.java new file mode 100644 index 00000000000..2c57ddaca7d --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AirshipEngineRoom.java @@ -0,0 +1,48 @@ +package mage.cards.a; + +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.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlueManaAbility; +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 AirshipEngineRoom extends CardImpl { + + public AirshipEngineRoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {R}. + this.addAbility(new BlueManaAbility()); + this.addAbility(new RedManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private AirshipEngineRoom(final AirshipEngineRoom card) { + super(card); + } + + @Override + public AirshipEngineRoom copy() { + return new AirshipEngineRoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java b/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java deleted file mode 100644 index 750cdcbb659..00000000000 --- a/Mage.Sets/src/mage/cards/a/AjaniNacatlAvenger.java +++ /dev/null @@ -1,190 +0,0 @@ -package mage.cards.a; - -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DamageTargetEffect; -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.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.CatWarrior21Token; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetAnyTarget; -import mage.util.CardUtil; - -import java.util.*; -import java.util.stream.Collectors; - -/** - * @author Susucr - */ -public final class AjaniNacatlAvenger extends CardImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control"); - - public AjaniNacatlAvenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AJANI); - this.setStartingLoyalty(3); - - this.color.setRed(true); - this.color.setWhite(true); - this.nightCard = true; - - // +2: Put a +1/+1 counter on each Cat you control. - this.addAbility(new LoyaltyAbility( - new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), 2 - )); - - // 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target. - this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0)); - - // -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest. - this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4)); - } - - private AjaniNacatlAvenger(final AjaniNacatlAvenger card) { - super(card); - } - - @Override - public AjaniNacatlAvenger copy() { - return new AjaniNacatlAvenger(this); - } -} - -class AjaniNacatlAvengerZeroEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}"); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(AnotherPredicate.instance); - } - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); - - AjaniNacatlAvengerZeroEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Create a 2/1 white Cat Warrior creature token. " - + "When you do, if you control a red permanent other than {this}, " - + "he deals damage equal to the number of creatures you control to any target."; - } - - private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) { - super(effect); - } - - @Override - public AjaniNacatlAvengerZeroEffect copy() { - return new AjaniNacatlAvengerZeroEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) { - return false; - } - - ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( - new DamageTargetEffect(CreaturesYouControlCount.PLURAL), - false, - "When you do, if you control a red permanent other than {this}, " - + "he deals damage equal to the number of creatures you control to any target.", - condition - ); - reflexive.addTarget(new TargetAnyTarget()); - game.fireReflexiveTriggeredAbility(reflexive, source); - return true; - } -} - -// Inspired by Mythos of Snapdax -class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect { - - private static final List cardTypes = Arrays.asList( - CardType.ARTIFACT, - CardType.CREATURE, - CardType.ENCHANTMENT, - CardType.PLANESWALKER - ); - - AjaniNacatlAvengerMinusFourEffect() { - super(Outcome.Benefit); - staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker " - + "from among the nonland permanents they control, then sacrifices the rest."; - } - - private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) { - super(effect); - } - - @Override - public AjaniNacatlAvengerMinusFourEffect copy() { - return new AjaniNacatlAvengerMinusFourEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - List playerList = game - .getOpponents(controller.getId()) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - Set toKeep = new HashSet<>(); - for (Player player : playerList) { - for (CardType cardType : cardTypes) { - String message = CardUtil.addArticle(cardType.toString()); - FilterPermanent filter = new FilterNonlandPermanent(message); - filter.add(cardType.getPredicate()); - filter.add(new ControllerIdPredicate(player.getId())); - if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { - continue; - } - TargetPermanent target = new TargetPermanent(filter); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - toKeep.add(target.getFirstTarget()); - } - } - - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) { - if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) { - continue; - } - permanent.sacrifice(source, game); - } - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java b/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java index 9320de6fd90..4019b4f0545 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java +++ b/Mage.Sets/src/mage/cards/a/AjaniNacatlPariah.java @@ -1,27 +1,49 @@ package mage.cards.a; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesOneOrMoreTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.CatWarrior21Token; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; /** * @author Susucr */ -public final class AjaniNacatlPariah extends CardImpl { +public final class AjaniNacatlPariah extends TransformingDoubleFacedCard { public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CAT, "other Cats you control"); + private static final FilterControlledCreaturePermanent nacatlAvengerFilter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control"); static { filter.add(AnotherPredicate.instance); @@ -29,25 +51,34 @@ public final class AjaniNacatlPariah extends CardImpl { } public AjaniNacatlPariah(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.CAT, SubType.WARRIOR}, "{1}{W}", + "Ajani, Nacatl Avenger", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.AJANI}, "RW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CAT); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.a.AjaniNacatlAvenger.class; + this.getLeftHalfCard().setPT(1, 2); + this.getRightHalfCard().setStartingLoyalty(3); // When Ajani, Nacatl Pariah enters the battlefield, create a 2/1 white Cat Warrior creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token()))); // Whenever one or more other Cats you control die, you may exile Ajani, then return him to the battlefield transformed under his owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesOneOrMoreTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesOneOrMoreTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), filter, true)); + + // Ajani, Nacatl Avenger + // +2: Put a +1/+1 counter on each Cat you control. + this.getRightHalfCard().addAbility(new LoyaltyAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), nacatlAvengerFilter), 2 + )); + + // 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0)); + + // -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4)); } private AjaniNacatlPariah(final AjaniNacatlPariah card) { @@ -59,3 +90,116 @@ public final class AjaniNacatlPariah extends CardImpl { return new AjaniNacatlPariah(this); } } + +class AjaniNacatlAvengerZeroEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); + + AjaniNacatlAvengerZeroEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "Create a 2/1 white Cat Warrior creature token. " + + "When you do, if you control a red permanent other than {this}, " + + "he deals damage equal to the number of creatures you control to any target."; + } + + private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) { + super(effect); + } + + @Override + public AjaniNacatlAvengerZeroEffect copy() { + return new AjaniNacatlAvengerZeroEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) { + return false; + } + + ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( + new DamageTargetEffect(CreaturesYouControlCount.PLURAL), + false, + "When you do, if you control a red permanent other than {this}, " + + "he deals damage equal to the number of creatures you control to any target.", + condition + ); + reflexive.addTarget(new TargetAnyTarget()); + game.fireReflexiveTriggeredAbility(reflexive, source); + return true; + } +} + +// Inspired by Mythos of Snapdax +class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect { + + private static final List cardTypes = Arrays.asList( + CardType.ARTIFACT, + CardType.CREATURE, + CardType.ENCHANTMENT, + CardType.PLANESWALKER + ); + + AjaniNacatlAvengerMinusFourEffect() { + super(Outcome.Benefit); + staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker " + + "from among the nonland permanents they control, then sacrifices the rest."; + } + + private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) { + super(effect); + } + + @Override + public AjaniNacatlAvengerMinusFourEffect copy() { + return new AjaniNacatlAvengerMinusFourEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + List playerList = game + .getOpponents(controller.getId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + Set toKeep = new HashSet<>(); + for (Player player : playerList) { + for (CardType cardType : cardTypes) { + String message = CardUtil.addArticle(cardType.toString()); + FilterPermanent filter = new FilterNonlandPermanent(message); + filter.add(cardType.getPredicate()); + filter.add(new ControllerIdPredicate(player.getId())); + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { + continue; + } + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + toKeep.add(target.getFirstTarget()); + } + } + + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) { + if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) { + continue; + } + permanent.sacrifice(source, game); + } + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/a/AllOutAssault.java b/Mage.Sets/src/mage/cards/a/AllOutAssault.java index 1e25977cabb..6e230b7819e 100644 --- a/Mage.Sets/src/mage/cards/a/AllOutAssault.java +++ b/Mage.Sets/src/mage/cards/a/AllOutAssault.java @@ -42,7 +42,7 @@ public final class AllOutAssault extends CardImpl { extraCombatAbility.addEffect(new CreateDelayedTriggeredAbilityEffect(new WhenYouAttackDelayedTriggeredAbility( new UntapAllControllerEffect( StaticFilters.FILTER_CONTROLLED_CREATURE, "untap each creature you control"), Duration.EndOfTurn, true))); - this.addAbility(extraCombatAbility.withInterveningIf(IsMainPhaseCondition.YOUR)); + this.addAbility(extraCombatAbility.withInterveningIf(IsMainPhaseCondition.YOURS)); } diff --git a/Mage.Sets/src/mage/cards/a/AlliesAtLast.java b/Mage.Sets/src/mage/cards/a/AlliesAtLast.java new file mode 100644 index 00000000000..be50ca1cdb0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AlliesAtLast.java @@ -0,0 +1,39 @@ +package mage.cards.a; + +import mage.abilities.effects.common.TargetsDamageTargetsEffect; +import mage.abilities.keyword.AffinityAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AffinityType; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AlliesAtLast extends CardImpl { + + public AlliesAtLast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Affinity for Allies + this.addAbility(new AffinityAbility(AffinityType.ALLIES)); + + // Up to two target creatures you control each deal damage equal to their power to target creature an opponent controls. + this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2).setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent().setTargetTag(3)); + } + + private AlliesAtLast(final AlliesAtLast card) { + super(card); + } + + @Override + public AlliesAtLast copy() { + return new AlliesAtLast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AlluringSuitor.java b/Mage.Sets/src/mage/cards/a/AlluringSuitor.java index b9ea71bbb06..229793ea3ac 100644 --- a/Mage.Sets/src/mage/cards/a/AlluringSuitor.java +++ b/Mage.Sets/src/mage/cards/a/AlluringSuitor.java @@ -1,35 +1,60 @@ package mage.cards.a; -import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.mana.UntilEndOfTurnManaEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.game.events.GameEvent; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class AlluringSuitor extends CardImpl { +public final class AlluringSuitor extends TransformingDoubleFacedCard { public AlluringSuitor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.d.DeadlyDancer.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{R}", + "Deadly Dancer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "R"); + this.getLeftHalfCard().setPT(2, 3); + this.getRightHalfCard().setPT(3, 3); // When you attack with exactly two creatures, transform Alluring Suitor. - this.addAbility(new TransformAbility()); - this.addAbility(new AlluringSuitorTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AlluringSuitorTriggeredAbility()); + + // Deadly Dancer + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // When this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new UntilEndOfTurnManaEffect(Mana.RedMana(2)))); + + // {R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn. + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ).setText("{this}"), new ManaCostsImpl<>("{R}{R}")); + ability.addEffect(new BoostTargetEffect(1, 0) + .setText("and another target creature each get +1/+0 until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.getRightHalfCard().addAbility(ability); } private AlluringSuitor(final AlluringSuitor card) { diff --git a/Mage.Sets/src/mage/cards/a/AloySaviorOfMeridian.java b/Mage.Sets/src/mage/cards/a/AloySaviorOfMeridian.java index eec53f63ede..11480f4120d 100644 --- a/Mage.Sets/src/mage/cards/a/AloySaviorOfMeridian.java +++ b/Mage.Sets/src/mage/cards/a/AloySaviorOfMeridian.java @@ -10,10 +10,7 @@ import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.VigilanceAbility; 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.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -42,8 +39,8 @@ public final class AloySaviorOfMeridian extends CardImpl { this.addAbility(ReachAbility.getInstance()); // In You, All Things Are Possible -- Whenever one or more artifact creatures you control attack, discover X, where X is the greatest power among them. - this.addAbility(new AttacksWithCreaturesTriggeredAbility( - new AloySaviorOfMeridianEffect(), 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE + this.addAbility(new AttacksWithCreaturesTriggeredAbility(Zone.BATTLEFIELD, + new AloySaviorOfMeridianEffect(), 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE, true ).setTriggerPhrase("Whenever one or more artifact creatures you control attack, ").withFlavorWord("In You, All Things Are Possible")); } diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java b/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java index ef84be1744f..0c7e34a60d2 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheWretched.java @@ -1,45 +1,63 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.*; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; +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; /** * * @author jeffwadsworth */ -public final class AltarOfTheWretched extends CardImpl { +public final class AltarOfTheWretched extends TransformingDoubleFacedCard { public AltarOfTheWretched(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}"); - this.secondSideCardClazz = mage.cards.w.WretchedBonemass.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{B}", + "Wretched Bonemass", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SKELETON, SubType.HORROR}, "B"); + this.getRightHalfCard().setPT(0, 0); // When Altar of the Wretched enters the battlefield, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creature’s power. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true)); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true)); // Craft with one or more creatures {2}{B}{B} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{2}{B}{B}", "one or more creatures", "other creatures you control and/or" + "creature cards in your graveyard", 1, Integer.MAX_VALUE, CardType.CREATURE.getPredicate() )); // {2}{B}: Return Altar of the Wretched from your graveyard to your hand. - this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}"))); + // Wretched Bonemass + // Wretched Bonemass’s power and toughness are each equal to the total power of the exiled cards used to craft it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(WretchedBonemassDynamicValue.instance).setText("{this}'s power and toughness are each equal to the total power of the exiled cards used to craft it."))); + + // Wretched Bonemass has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new WretchedBonemassGainAbilityEffect())); } private AltarOfTheWretched(final AltarOfTheWretched card) { @@ -84,3 +102,124 @@ class AltarOfTheWretchedEffect extends OneShotEffect { return new AltarOfTheWretchedEffect(this); } } + + +enum WretchedBonemassDynamicValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int totalPower = 0; + Permanent permanent = sourceAbility.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return 0; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, permanent.getMainCard().getId(), permanent.getZoneChangeCounter(game) - 1 + )); + if (exileZone == null) { + return 0; + } + for (Card card : exileZone.getCards(game)) { + totalPower += card.getPower().getValue(); + } + return totalPower; + } + + @Override + public WretchedBonemassDynamicValue copy() { + return this; + } + + @Override + public String getMessage() { + return "total power of the exiled cards used to craft it"; + } + + @Override + public String toString() { + return "0"; + } +} + +class WretchedBonemassGainAbilityEffect extends ContinuousEffectImpl { + + WretchedBonemassGainAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "{this} has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance."; + } + + private WretchedBonemassGainAbilityEffect(final WretchedBonemassGainAbilityEffect effect) { + super(effect); + } + + @Override + public WretchedBonemassGainAbilityEffect copy() { + return new WretchedBonemassGainAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent wretchedBonemass = source.getSourcePermanentIfItStillExists(game); + if (wretchedBonemass != null) { + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, wretchedBonemass.getMainCard().getId(), wretchedBonemass.getZoneChangeCounter(game) - 1 + )); + if (exileZone != null + && !exileZone.isEmpty()) { + Set cardsInExile = exileZone.getCards(game); + for (Card card : cardsInExile) { + for (Ability a : card.getAbilities()) { + if (a instanceof FlyingAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof FirstStrikeAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DoubleStrikeAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DeathtouchAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HasteAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HexproofAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof LifelinkAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof MenaceAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ProtectionAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ReachAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof TrampleAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + if (a instanceof VigilanceAbility) { + wretchedBonemass.addAbility(a, source.getSourceId(), game); + } + } + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AmarethTheLustrous.java b/Mage.Sets/src/mage/cards/a/AmarethTheLustrous.java index 8cd758c8a31..4589a8833ec 100644 --- a/Mage.Sets/src/mage/cards/a/AmarethTheLustrous.java +++ b/Mage.Sets/src/mage/cards/a/AmarethTheLustrous.java @@ -10,8 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -23,12 +22,6 @@ import java.util.UUID; */ public final class AmarethTheLustrous extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public AmarethTheLustrous(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{U}"); @@ -41,7 +34,9 @@ public final class AmarethTheLustrous extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever another permanent you control enters, look at the top card of your library. If it shares a card type with that permanent, you may reveal that card and put it into your hand. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new AmarethTheLustrousEffect(), filter)); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new AmarethTheLustrousEffect(), StaticFilters.FILTER_ANOTHER_PERMANENT + )); } private AmarethTheLustrous(final AmarethTheLustrous card) { diff --git a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java b/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java index b92a884539b..761eda04c28 100644 --- a/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java +++ b/Mage.Sets/src/mage/cards/a/AmbitiousFarmhand.java @@ -1,6 +1,5 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CovenCondition; @@ -8,9 +7,9 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.CovenHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -22,27 +21,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AmbitiousFarmhand extends CardImpl { +public final class AmbitiousFarmhand extends TransformingDoubleFacedCard { public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{W}", + "Seasoned Cathar", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "W"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SeasonedCathar.class; + // Ambitious Farmhand + this.getLeftHalfCard().setPT(1, 1); // When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true )); // Coven—{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance ).setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance)); + + // Seasoned Cathar + this.getRightHalfCard().setPT(3, 3); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); } private AmbitiousFarmhand(final AmbitiousFarmhand card) { diff --git a/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java b/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java index 45af92015a5..ef74b2c0b17 100644 --- a/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java +++ b/Mage.Sets/src/mage/cards/a/AnakinSkywalker.java @@ -1,18 +1,22 @@ package mage.cards.a; -import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -20,38 +24,45 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.Iterator; import java.util.UUID; /** * @author Styxo */ -public final class AnakinSkywalker extends CardImpl { +public final class AnakinSkywalker extends TransformingDoubleFacedCard { public AnakinSkywalker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}{R}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SITH); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.d.DarthVader.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "{3}{U}{B}{R}", + "Darth Vader", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "B"); + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(4, 4); // Whenever another creature dies, put a +1/+1 counter on Anakin Skywalker. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); // Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // If Anakin Skywalker would be destroyed, regenerate, then transform him instead. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect())); + + // Darth Vader + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Whenever Darth Vader attacks, creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new UnboostCreaturesDefendingPlayerEffect(), false, null, SetTargetPointer.PLAYER)); } @@ -101,3 +112,47 @@ class AnakinSkywalkerEffect extends ReplacementEffectImpl { return new AnakinSkywalkerEffect(this); } } + + +class UnboostCreaturesDefendingPlayerEffect extends ContinuousEffectImpl { + + UnboostCreaturesDefendingPlayerEffect() { + super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature); + staticText = "creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader"; + } + + private UnboostCreaturesDefendingPlayerEffect(final UnboostCreaturesDefendingPlayerEffect effect) { + super(effect); + } + + @Override + public UnboostCreaturesDefendingPlayerEffect copy() { + return new UnboostCreaturesDefendingPlayerEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (getAffectedObjectsSet()) { + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getTargetPointer().getFirst(game, source), game)) { + 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) { + int unboostCount = -1 * new CountersSourceCount(CounterType.P1P1).calculate(game, source, this); + permanent.addPower(unboostCount); + permanent.addToughness(unboostCount); + } else { + it.remove(); + } + } + return true; + } +} + diff --git a/Mage.Sets/src/mage/cards/a/AncestorsEmbrace.java b/Mage.Sets/src/mage/cards/a/AncestorsEmbrace.java deleted file mode 100644 index ce046048700..00000000000 --- a/Mage.Sets/src/mage/cards/a/AncestorsEmbrace.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.a; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AncestorsEmbrace extends CardImpl { - - public AncestorsEmbrace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has lifelink. - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( - LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield - ))); - - // If Ancestor's Embrace would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private AncestorsEmbrace(final AncestorsEmbrace card) { - super(card); - } - - @Override - public AncestorsEmbrace copy() { - return new AncestorsEmbrace(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java b/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java deleted file mode 100644 index af17bdb0e39..00000000000 --- a/Mage.Sets/src/mage/cards/a/AncientOfTheEquinox.java +++ /dev/null @@ -1,42 +0,0 @@ - -package mage.cards.a; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author LevelX2 - */ -public final class AncientOfTheEquinox extends CardImpl { - - public AncientOfTheEquinox(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.TREEFOLK); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - } - - private AncientOfTheEquinox(final AncientOfTheEquinox card) { - super(card); - } - - @Override - public AncientOfTheEquinox copy() { - return new AncientOfTheEquinox(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java b/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java deleted file mode 100644 index 4a28dd92a8d..00000000000 --- a/Mage.Sets/src/mage/cards/a/AngelicEnforcer.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.ControllerLifeCount; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -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.Zone; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AngelicEnforcer extends CardImpl { - - public AngelicEnforcer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // You have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); - - // Angelic Enforcer's power and toughness are each equal to your life total. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect( - ControllerLifeCount.instance - ).setText("{this}'s power and toughness are each equal to your life total"))); - - // Whenever Angelic Enforcer attacks, double your life total. - this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect( - ControllerLifeCount.instance - ).setText("double your life total"))); - } - - private AngelicEnforcer(final AngelicEnforcer card) { - super(card); - } - - @Override - public AngelicEnforcer copy() { - return new AngelicEnforcer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java b/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java deleted file mode 100644 index ec8de09da90..00000000000 --- a/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.hint.Hint; -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.filter.FilterCard; -import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.card.DefendingPlayerOwnsCardPredicate; -import mage.game.Game; - -import java.util.Objects; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author TheElk801 - */ -public final class AnimusOfNightsReach extends CardImpl { - - private static final FilterCard filter - = new FilterCreatureCard("creature cards in defending player's graveyard"); - - static { - filter.add(DefendingPlayerOwnsCardPredicate.instance); - } - - private static final DynamicValue xValue = new CardsInAllGraveyardsCount(filter); - - public AnimusOfNightsReach(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // 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 - ).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) { - super(card); - } - - @Override - public AnimusOfNightsReach copy() { - return new AnimusOfNightsReach(this); - } -} - -enum AnimusOfNightsReachHint implements Hint { - instance; - - @Override - public String getText(Game game, Ability ability) { - return "Cards in each opponent's graveyard:
" - + game - .getOpponents(ability.getControllerId()) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .map(player -> player - .getName() - + ": " + player - .getGraveyard() - .count(StaticFilters.FILTER_CARD_CREATURE, game)) - .collect(Collectors.joining("
")); - } - - @Override - public AnimusOfNightsReachHint copy() { - return instance; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AnotherChance.java b/Mage.Sets/src/mage/cards/a/AnotherChance.java index fbbd9705b6c..852c2354d48 100644 --- a/Mage.Sets/src/mage/cards/a/AnotherChance.java +++ b/Mage.Sets/src/mage/cards/a/AnotherChance.java @@ -2,17 +2,15 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.OneShotNonTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; 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 mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -26,7 +24,9 @@ public final class AnotherChance extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // You may mill two cards. Then return up to two creature cards from your graveyard to your hand. - this.getSpellAbility().addEffect(new AnotherChanceEffect()); + this.getSpellAbility().addEffect(new AnotherChanceMillEffect()); + this.getSpellAbility().addEffect(new OneShotNonTargetEffect(new ReturnFromGraveyardToHandTargetEffect().setText("Then return up to two creature cards from your graveyard to your hand."), + new TargetCardInYourGraveyard(0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true)).withTargetDescription("up to two creature cards")); } private AnotherChance(final AnotherChance card) { @@ -39,23 +39,20 @@ public final class AnotherChance extends CardImpl { } } -/** - * Inspired by {@link mage.cards.u.UnsealTheNecropolis} - */ -class AnotherChanceEffect extends OneShotEffect { +class AnotherChanceMillEffect extends OneShotEffect { - AnotherChanceEffect() { + AnotherChanceMillEffect() { super(Outcome.Benefit); - staticText = "You may mill two cards. Then return up to two creature cards from your graveyard to your hand"; + staticText = "You may mill two cards."; } - private AnotherChanceEffect(final AnotherChanceEffect effect) { + private AnotherChanceMillEffect(final AnotherChanceMillEffect effect) { super(effect); } @Override - public AnotherChanceEffect copy() { - return new AnotherChanceEffect(this); + public AnotherChanceMillEffect copy() { + return new AnotherChanceMillEffect(this); } @Override @@ -68,18 +65,6 @@ class AnotherChanceEffect extends OneShotEffect { if (player.chooseUse(outcome, "Mill two cards?", source, game)) { player.millCards(2, source, game); } - - // Make sure the mill has been processed. - game.processAction(); - - TargetCard target = new TargetCardInYourGraveyard( - 0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true - ); - player.choose(outcome, target, source, game); - Cards cards = new CardsImpl(target.getTargets()); - if (!cards.isEmpty()) { - player.moveCards(cards, Zone.HAND, source, game); - } return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ApexObservatory.java b/Mage.Sets/src/mage/cards/a/ApexObservatory.java deleted file mode 100644 index 47f9acc8c89..00000000000 --- a/Mage.Sets/src/mage/cards/a/ApexObservatory.java +++ /dev/null @@ -1,241 +0,0 @@ -package mage.cards.a; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.AsEntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceCardType; -import mage.constants.*; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; - -import java.util.*; -import java.util.stream.Collectors; -import mage.abilities.SpellAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; - -/** - * @author jeffwadsworth - */ -public class ApexObservatory extends CardImpl { - - public ApexObservatory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, null); - - this.nightCard = true; - - // Apex Observatory enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); - - // As it enters, choose a card type shared among two exiled cards used to craft it. - this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect())); - - // The next spell you cast this turn of the chosen type can be cast without paying its mana cost. - this.addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost())); - } - - private ApexObservatory(final ApexObservatory card) { - super(card); - } - - @Override - public ApexObservatory copy() { - return new ApexObservatory(this); - } -} - -class ChooseCardTypeEffect extends OneShotEffect { - - public ChooseCardTypeEffect() { - super(Outcome.Neutral); - staticText = "choose a card type shared among two exiled cards used to craft it."; - } - - protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getPermanentEntering(source.getSourceId()); - List exiledCardsCardType = new ArrayList<>(); - if (mageObject == null) { - mageObject = game.getObject(source); - } - if (controller != null && mageObject != null) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - // chase the exile zone down... - ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source, game.getState().getZoneChangeCounter(mageObject.getId()) - 1)); - if (exileZone == null) { - return false; - } - for (Card card : exileZone.getCards(game)) { - exiledCardsCardType.addAll(card.getCardType(game)); - } - Choice cardTypeChoice = new ChoiceCardType(); - cardTypeChoice.getChoices().clear(); - cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList())); - // find only card types that each card shares; some cards have more than 1 card type - Map cardTypeCounts = new HashMap<>(); - for (String cardType : cardTypeChoice.getChoices()) { - cardTypeCounts.put(cardType, 0); - } - - for (Card c : exileZone.getCards(game)) { - for (CardType cardType : c.getCardType(game)) { - if (cardTypeCounts.containsKey(cardType.toString())) { - cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1); - } - } - } - - List sharedCardTypes = new ArrayList<>(); - int numExiledCards = exileZone.getCards(game).size(); - for (Map.Entry entry : cardTypeCounts.entrySet()) { - if (entry.getValue() == numExiledCards) { - sharedCardTypes.add(entry.getKey()); - } - } - // handle situations like the double-faced instant/land Jwari Disruption // Jwari Ruins - if (sharedCardTypes.isEmpty()) { - game.informPlayers(mageObject.getIdName() + " No exiled cards shared a type in exile, so nothing is done."); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("No exiled cards have the same card type."), game); - } - return false; - } - cardTypeChoice.getChoices().retainAll(sharedCardTypes); - if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) { - if (!game.isSimulation()) { - game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice()); - } - game.getState().setValue("ApexObservatoryType_" + source.getSourceId().toString(), cardTypeChoice.getChoice()); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game); - } - return true; - } - } - return false; - } - - @Override - public ChooseCardTypeEffect copy() { - return new ChooseCardTypeEffect(this); - } -} - -class ApexObservatoryEffect extends OneShotEffect { - - ApexObservatoryEffect() { - super(Outcome.Benefit); - staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost."; - } - - private ApexObservatoryEffect(final ApexObservatoryEffect effect) { - super(effect); - } - - @Override - public ApexObservatoryEffect copy() { - return new ApexObservatoryEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString()); - if (chosenCardType == null) { - return false; - } - game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source); - return true; - } -} - -class ApexObservatoryCastWithoutManaEffect extends CostModificationEffectImpl { - - private final String chosenCardType; - private final UUID playerId; - private boolean used = false; - - ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) { - super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.SET_COST); - this.chosenCardType = chosenCardType; - this.playerId = playerId; - staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost"; - } - - private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) { - super(effect); - this.chosenCardType = effect.chosenCardType; - this.playerId = effect.playerId; - this.used = effect.used; - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - // Ask the player if they want to use the effect - Player controller = game.getPlayer(playerId); - if (controller != null) { - MageObject spell = abilityToModify.getSourceObject(game); - if (spell != null && !game.isSimulation()) { - String message = "Cast " + spell.getIdName() + " without paying its mana cost?"; - if (controller.chooseUse(Outcome.Benefit, message, source, game)) { - // Set the cost to zero - abilityToModify.getManaCostsToPay().clear(); - // Mark as used - used = true; - game.informPlayers(controller.getLogName() + " casts " + spell.getIdName() + " without paying its mana cost."); - return true; - } else { - // Player chose not to use the effect - return false; - } - } - } - return false; - } - - @Override - public ApexObservatoryCastWithoutManaEffect copy() { - return new ApexObservatoryCastWithoutManaEffect(this); - } - - @Override - public boolean isInactive(Ability source, Game game) { - return used || super.isInactive(source, game); - } - - @Override - public boolean applies(Ability ability, Ability source, Game game) { - if (used) { - return false; - } - if (!ability.isControlledBy(playerId)) { - return false; - } - if (!(ability instanceof SpellAbility)) { - return false; - } - MageObject object = game.getObject(ability.getSourceId()); - if (object != null && object.getCardType(game).stream() - .anyMatch(cardType -> cardType.toString().equals(chosenCardType))) { - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java b/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java new file mode 100644 index 00000000000..337f02de580 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AppaLoyalSkyBison.java @@ -0,0 +1,66 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AppaLoyalSkyBison extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public AppaLoyalSkyBison(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BISON); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Appa enters or attacks, choose one -- + // * Target creature you control gains flying until end of turn. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); + ability.addTarget(new TargetControlledCreaturePermanent()); + + // * Airbend another target nonland permanent you control. + ability.addMode(new Mode(new AirbendTargetEffect()).addTarget(new TargetPermanent(filter))); + this.addAbility(ability); + } + + private AppaLoyalSkyBison(final AppaLoyalSkyBison card) { + super(card); + } + + @Override + public AppaLoyalSkyBison copy() { + return new AppaLoyalSkyBison(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AppaTheVigilant.java b/Mage.Sets/src/mage/cards/a/AppaTheVigilant.java new file mode 100644 index 00000000000..517110654e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AppaTheVigilant.java @@ -0,0 +1,68 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +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.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AppaTheVigilant extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Ally"); + + public AppaTheVigilant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BISON); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever Appa or another Ally you control enters, creatures you control get +1/+1 and gain flying and vigilance until end of turn. + Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn) + .setText("creatures you control get +1/+1"), + filter, false, true + ); + ability.addEffect(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and gain flying")); + ability.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and vigilance until end of turn")); + this.addAbility(ability); + } + + private AppaTheVigilant(final AppaTheVigilant card) { + super(card); + } + + @Override + public AppaTheVigilant copy() { + return new AppaTheVigilant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AprilONeilHacktivist.java b/Mage.Sets/src/mage/cards/a/AprilONeilHacktivist.java new file mode 100644 index 00000000000..d052f3f0523 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AprilONeilHacktivist.java @@ -0,0 +1,132 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.Hint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class AprilONeilHacktivist extends CardImpl { + + public AprilONeilHacktivist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // At the beginning of your end step, draw a card for each card type among spells you've cast this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new DrawCardSourceControllerEffect(AprilONeilHacktivistValue.instance) + ).addHint(AprilONeilHacktivistHint.instance), new AprilONeilHacktivistWatcher()); + } + + private AprilONeilHacktivist(final AprilONeilHacktivist card) { + super(card); + } + + @Override + public AprilONeilHacktivist copy() { + return new AprilONeilHacktivist(this); + } +} + +enum AprilONeilHacktivistValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return AprilONeilHacktivistWatcher.getCardTypesCast(sourceAbility.getControllerId(), game).size(); + } + + @Override + public AprilONeilHacktivistValue copy() { + return this; + } + + @Override + public String getMessage() { + return "card type among spells you've cast this turn"; + } + + @Override + public String toString() { + return "1"; + } +} + +enum AprilONeilHacktivistHint implements Hint { + instance; + + + @Override + public String getText(Game game, Ability ability) { + List types = AprilONeilHacktivistWatcher + .getCardTypesCast(ability.getControllerId(), game) + .stream() + .map(CardType::toString) + .sorted() + .collect(Collectors.toList()); + return "Card types among spells you've cast this turn: " + types.size() + + (types.size() > 0 ? " (" + String.join(", ", types) + ')' : ""); + } + + @Override + public Hint copy() { + return this; + } +} + +class AprilONeilHacktivistWatcher extends Watcher { + + private final Map> map = new HashMap<>(); + + AprilONeilHacktivistWatcher() { + 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) { + map.computeIfAbsent(spell.getControllerId(), x -> new HashSet<>()).addAll(spell.getCardType(game)); + } + } + + @Override + public void reset() { + map.clear(); + super.reset(); + } + + static Set getCardTypesCast(UUID playerId, Game game) { + return game + .getState() + .getWatcher(AprilONeilHacktivistWatcher.class) + .map + .getOrDefault(playerId, Collections.emptySet()); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcTrail.java b/Mage.Sets/src/mage/cards/a/ArcTrail.java index a85ec5afa8e..e0a9fe36d2d 100644 --- a/Mage.Sets/src/mage/cards/a/ArcTrail.java +++ b/Mage.Sets/src/mage/cards/a/ArcTrail.java @@ -1,21 +1,15 @@ package mage.cards.a; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetPermanentOrPlayer; -import java.io.ObjectStreamException; import java.util.UUID; /** @@ -23,8 +17,7 @@ import java.util.UUID; */ public final class ArcTrail extends CardImpl { - private static final FilterPermanentOrPlayer filter1 = new FilterAnyTarget("creature, player or planeswalker to deal 2 damage"); - private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another creature, player or planeswalker to deal 1 damage"); + private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another target"); static { filter2.getPermanentFilter().add(new AnotherTargetPredicate(2)); @@ -34,10 +27,12 @@ public final class ArcTrail extends CardImpl { public ArcTrail(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); - // Arc Trail deals 2 damage to any target and 1 damage to another any target - this.getSpellAbility().addEffect(ArcTrailEffect.getInstance()); - this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter1).setTargetTag(1)); - this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter2).setTargetTag(2)); + // Arc Trail deals 2 damage to any target and 1 damage to another target + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 1)); + this.getSpellAbility().addTarget(new TargetAnyTarget() + .withChooseHint("to deal 2 damage").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter2) + .withChooseHint("to deal 1 damage").setTargetTag(2)); } private ArcTrail(final ArcTrail card) { @@ -50,54 +45,3 @@ public final class ArcTrail extends CardImpl { } } - -class ArcTrailEffect extends OneShotEffect { - - private static final ArcTrailEffect instance = new ArcTrailEffect(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static ArcTrailEffect getInstance() { - return instance; - } - - private ArcTrailEffect() { - super(Outcome.Damage); - staticText = "{this} deals 2 damage to any target and 1 damage to another target"; - } - - @Override - public boolean apply(Game game, Ability source) { - - boolean applied = false; - boolean twoDamageDone = false; - int damage = 2; - - for (Target target : source.getTargets()) { - Permanent permanent = game.getPermanent(target.getFirstTarget()); - - if (twoDamageDone) { - damage = 1; - } - - if (permanent != null) { - applied |= (permanent.damage(damage, source.getSourceId(), source, game, false, true) > 0); - } - Player player = game.getPlayer(target.getFirstTarget()); - if (player != null) { - applied |= (player.damage(damage, source.getSourceId(), source, game) > 0); - } - - twoDamageDone = true; - } - return applied; - } - - @Override - public ArcTrailEffect copy() { - return instance; - } - -} diff --git a/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java b/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java deleted file mode 100644 index 93028094ebc..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArceeAcrobaticCoupe.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.dynamicvalue.common.SavedDamageValue; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.target.Target; - -import java.util.Collection; -import java.util.Objects; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ArceeAcrobaticCoupe extends CardImpl { - - public ArceeAcrobaticCoupe(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setRed(true); - this.color.setWhite(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee. - this.addAbility(new ArceeAcrobaticCoupeTriggeredAbility()); - } - - private ArceeAcrobaticCoupe(final ArceeAcrobaticCoupe card) { - super(card); - } - - @Override - public ArceeAcrobaticCoupe copy() { - return new ArceeAcrobaticCoupe(this); - } -} - -class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility { - - ArceeAcrobaticCoupeTriggeredAbility() { - super(new AddCountersSourceEffect( - CounterType.P1P1.createInstance(0), - SavedDamageValue.MANY, false - ), false); - this.addEffect(new TransformSourceEffect()); - } - - private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) { - super(ability); - } - - @Override - public ArceeAcrobaticCoupeTriggeredAbility copy() { - return new ArceeAcrobaticCoupeTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!super.checkTrigger(event, game)) { - return false; - } - Spell spell = game.getSpell(event.getTargetId()); - if (spell == null) { - return false; - } - int targets = spell - .getStackAbility() - .getTargets() - .stream() - .map(Target::getTargets) - .flatMap(Collection::stream) - .map(game::getPermanent) - .filter(Objects::nonNull) - .filter(permanent -> permanent.isCreature(game) - || permanent.hasSubtype(SubType.VEHICLE, game)) - .map(Controllable::getControllerId) - .map(this::isControlledBy) - .mapToInt(x -> x ? 1 : 0) - .sum(); - if (targets > 0) { - this.getEffects().setValue("damage", targets); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast a spell that targets one or more creatures or Vehicles " + - "you control, put that many +1/+1 counters on {this}. Convert {this}."; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java b/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java index 5376b5b76a3..a606ec7d07e 100644 --- a/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java +++ b/Mage.Sets/src/mage/cards/a/ArceeSharpshooter.java @@ -1,44 +1,54 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import java.util.Collection; +import java.util.Objects; import java.util.UUID; /** * @author TheElk801 */ -public final class ArceeSharpshooter extends CardImpl { +public final class ArceeSharpshooter extends TransformingDoubleFacedCard { public ArceeSharpshooter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{R}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{1}{R}{W}", + "Arcee, Acrobatic Coupe", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "RW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.a.ArceeAcrobaticCoupe.class; + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(2, 2); // More Than Meets the Eye {R}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}")); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // {1}, Remove one or more +1/+1 counters from Arcee: It deals that much damage to target creature. Convert Arcee. Ability ability = new SimpleActivatedAbility( @@ -49,7 +59,14 @@ public final class ArceeSharpshooter extends CardImpl { ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1, 1)); ability.addEffect(new TransformSourceEffect().setText("convert {this}")); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Arcee, Acrobatic Coupe + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee. + this.getRightHalfCard().addAbility(new ArceeAcrobaticCoupeTriggeredAbility()); } private ArceeSharpshooter(final ArceeSharpshooter card) { @@ -61,3 +78,59 @@ public final class ArceeSharpshooter extends CardImpl { return new ArceeSharpshooter(this); } } + +class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility { + + ArceeAcrobaticCoupeTriggeredAbility() { + super(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(0), + SavedDamageValue.MANY, false + ), false); + this.addEffect(new TransformSourceEffect()); + } + + private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) { + super(ability); + } + + @Override + public ArceeAcrobaticCoupeTriggeredAbility copy() { + return new ArceeAcrobaticCoupeTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return false; + } + int targets = spell + .getStackAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .map(game::getPermanent) + .filter(Objects::nonNull) + .filter(permanent -> permanent.isCreature(game) + || permanent.hasSubtype(SubType.VEHICLE, game)) + .map(Controllable::getControllerId) + .map(this::isControlledBy) + .mapToInt(x -> x ? 1 : 0) + .sum(); + if (targets > 0) { + this.getEffects().setValue("damage", targets); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast a spell that targets one or more creatures or Vehicles " + + "you control, put that many +1/+1 counters on {this}. Convert {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java b/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java index 6f4b2eb2aa9..34a0e408081 100644 --- a/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java +++ b/Mage.Sets/src/mage/cards/a/ArchangelAvacyn.java @@ -1,66 +1,86 @@ package mage.cards.a; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.*; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.mageobject.AnotherPredicate; import java.util.UUID; /** * @author fireshoes */ -public final class ArchangelAvacyn extends CardImpl { +public final class ArchangelAvacyn extends TransformingDoubleFacedCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a non-Angel creature you control"); + private static final FilterCreaturePermanent nonAngelFilter = new FilterCreaturePermanent("a non-Angel creature you control"); + private static final FilterPermanent otherCreatureFilter = new FilterCreaturePermanent("other creature"); static { - filter.add(Predicates.not(SubType.ANGEL.getPredicate())); - filter.add(TargetController.YOU.getControllerPredicate()); + otherCreatureFilter.add(AnotherPredicate.instance); + nonAngelFilter.add(Predicates.not(SubType.ANGEL.getPredicate())); + nonAngelFilter.add(TargetController.YOU.getControllerPredicate()); } public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{3}{W}{W}", + "Avacyn, the Purifier", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "R"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.a.AvacynThePurifier.class; + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 5); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES ), false)); // When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect()) - ).setText("transform {this} at the beginning of the next upkeep"), false, filter + ).setText("transform {this} at the beginning of the next upkeep"), false, nonAngelFilter ).setTriggerPhrase("When a non-Angel creature you control dies, ")); + + // Avacyn, the Purifier + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. + Ability ability = new TransformIntoSourceTriggeredAbility( + new DamageAllEffect(3, "it", otherCreatureFilter) + ); + ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent")); + this.getRightHalfCard().addAbility(ability); } private ArchangelAvacyn(final ArchangelAvacyn card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java b/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java deleted file mode 100644 index 6698dcde482..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TapSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; - -import java.util.UUID; - -/** - * @author anonymous - */ -public final class ArchdemonOfGreed extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.HUMAN, "Human"); - - public ArchdemonOfGreed(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.DEMON); - this.color.setBlack(true); - - this.nightCard = true; - - this.power = new MageInt(9); - this.toughness = new MageInt(9); - - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(TrampleAbility.getInstance()); - - // At the beginning of your upkeep, sacrifice a Human. If you can't, tap Archdemon of Greed and it deals 9 damage to you. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( - null, new TapSourceEffect(), new SacrificeTargetCost(filter), false - ).addOtherwiseEffect(new DamageControllerEffect(9)) - .setText("sacrifice a Human. If you can't, tap {this} and it deals 9 damage to you"))); - } - - private ArchdemonOfGreed(final ArchdemonOfGreed card) { - super(card); - } - - @Override - public ArchdemonOfGreed copy() { - return new ArchdemonOfGreed(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArchitectOfRestoration.java b/Mage.Sets/src/mage/cards/a/ArchitectOfRestoration.java deleted file mode 100644 index 7796e0f603a..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArchitectOfRestoration.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.AttacksOrBlocksTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -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.SpiritToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ArchitectOfRestoration extends CardImpl { - - public ArchitectOfRestoration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.FOX); - this.subtype.add(SubType.MONK); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Whenever Architect of Restoration attacks or blocks, create a 1/1 colorless Spirit creature token. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateTokenEffect(new SpiritToken()), false)); - } - - private ArchitectOfRestoration(final ArchitectOfRestoration card) { - super(card); - } - - @Override - public ArchitectOfRestoration copy() { - return new ArchitectOfRestoration(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArchiveHaunt.java b/Mage.Sets/src/mage/cards/a/ArchiveHaunt.java deleted file mode 100644 index b4fac23a008..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArchiveHaunt.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.DrawDiscardControllerEffect; -import mage.abilities.keyword.DisturbAbility; -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 ArchiveHaunt extends CardImpl { - - public ArchiveHaunt(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Archive Haunt attacks, draw a card, then discard a card. - this.addAbility(new AttacksTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); - - // If Archive Haunt would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private ArchiveHaunt(final ArchiveHaunt card) { - super(card); - } - - @Override - public ArchiveHaunt copy() { - return new ArchiveHaunt(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java b/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java index d6966008224..a7787944d99 100644 --- a/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java +++ b/Mage.Sets/src/mage/cards/a/ArguelsBloodFast.java @@ -1,42 +1,56 @@ package mage.cards.a; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class ArguelsBloodFast extends CardImpl { +public final class ArguelsBloodFast extends TransformingDoubleFacedCard { public ArguelsBloodFast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.t.TempleOfAclazotz.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{B}", + "Temple of Aclazotz", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{},""); // {1}{B}, Pay 2 life: Draw a card. Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new PayLifeCost(2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your upkeep, if you have 5 or less life, you may transform Arguel's Blood Fast. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true ).withInterveningIf(FatefulHourCondition.instance)); + + // Temple of Aclazotz + // {T}: Add {B} + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // {T}, Sacrifice a creature: You gain life equal to the sacrificed creature's toughness. + Ability activatedAbility = new SimpleActivatedAbility(new GainLifeEffect(SacrificeCostCreaturesToughness.instance) + .setText("you gain life equal to the sacrificed creature's toughness"), new TapSourceCost()); + activatedAbility.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); + this.getRightHalfCard().addAbility(activatedAbility); } private ArguelsBloodFast(final ArguelsBloodFast card) { diff --git a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java b/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java deleted file mode 100644 index 8a6b011c2e0..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArlinnEmbracedByTheMoon.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.a; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -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.game.command.emblems.ArlinnEmbracedByTheMoonEmblem; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class ArlinnEmbracedByTheMoon extends CardImpl { - - public ArlinnEmbracedByTheMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.color.setRed(true); - this.color.setGreen(true); - - this.nightCard = true; - - // +1: Creatures you control get +1/+1 and gain trample until end of turn. - Ability ability = new LoyaltyAbility(new BoostControlledEffect( - 1, 1, Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("Creatures you control get +1/+1"), 1); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("and gain trample until end of turn")); - this.addAbility(ability); - - // -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon. - this.addAbility(new TransformAbility()); - ability = new LoyaltyAbility(new DamageTargetEffect(3), -1); - ability.addTarget(new TargetAnyTarget()); - ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); - - // -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'" - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6)); - } - - private ArlinnEmbracedByTheMoon(final ArlinnEmbracedByTheMoon card) { - super(card); - } - - @Override - public ArlinnEmbracedByTheMoon copy() { - return new ArlinnEmbracedByTheMoon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArlinnKord.java b/Mage.Sets/src/mage/cards/a/ArlinnKord.java index dbb9593deb6..b0c98a77768 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnKord.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnKord.java @@ -3,19 +3,26 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem; import mage.game.permanent.token.WolfToken; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -23,16 +30,14 @@ import java.util.UUID; /** * @author fireshoes */ -public final class ArlinnKord extends CardImpl { +public final class ArlinnKord extends TransformingDoubleFacedCard { public ArlinnKord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - - this.secondSideCardClazz = mage.cards.a.ArlinnEmbracedByTheMoon.class; - - this.setStartingLoyalty(3); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}", + "Arlinn, Embraced by the Moon", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG"); + this.getLeftHalfCard().setStartingLoyalty(3); // +1: Until end of turn, up to one target creature gets +2/+2 and gains vigilance and haste. Ability ability = new LoyaltyAbility(new BoostTargetEffect( @@ -45,13 +50,34 @@ public final class ArlinnKord extends CardImpl { HasteAbility.getInstance(), Duration.EndOfTurn ).setText("and haste")); ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // 0: Create a 2/2 green Wolf creature token. Transform Arlinn Kord. - this.addAbility(new TransformAbility()); ability = new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0); ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Arlinn, Embraced by the Moon + // +1: Creatures you control get +1/+1 and gain trample until end of turn. + ability = new LoyaltyAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("Creatures you control get +1/+1"), 1); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and gain trample until end of turn")); + this.getRightHalfCard().addAbility(ability); + + // -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon. + ability = new LoyaltyAbility(new DamageTargetEffect(3), -1); + ability.addTarget(new TargetAnyTarget()); + ability.addEffect(new TransformSourceEffect()); + this.getRightHalfCard().addAbility(ability); + + // -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'" + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6)); + } private ArlinnKord(final ArlinnKord card) { diff --git a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java b/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java deleted file mode 100644 index bc906251947..00000000000 --- a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java +++ /dev/null @@ -1,118 +0,0 @@ -package mage.cards.a; - -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.TrampleAbility; -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 ArlinnTheMoonsFury extends CardImpl { - - public ArlinnTheMoonsFury(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.setStartingLoyalty(4); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Nightbound - this.addAbility(new NightboundAbility()); - - // +2: Add {R}{G}. - this.addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana( - 0, 0, 0, 1, 1, 0, 0, 0 - )), 2)); - - // 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste. - this.addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0)); - } - - private ArlinnTheMoonsFury(final ArlinnTheMoonsFury card) { - super(card); - } - - @Override - public ArlinnTheMoonsFury copy() { - return new ArlinnTheMoonsFury(this); - } -} - -class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl { - - ArlinnTheMoonsFuryEffect() { - super(Duration.EndOfTurn, Outcome.Benefit); - staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste"; - this.dependencyTypes.add(DependencyType.BecomeCreature); - } - - private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) { - super(effect); - } - - @Override - public ArlinnTheMoonsFuryEffect copy() { - return new ArlinnTheMoonsFuryEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - discard(); - return false; - } - switch (layer) { - case TypeChangingEffects_4: - permanent.removeAllCardTypes(game); - permanent.addCardType(game, CardType.CREATURE); - permanent.removeAllCreatureTypes(game); - permanent.addSubType(game, SubType.WEREWOLF); - return true; - case AbilityAddingRemovingEffects_6: - permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); - permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game); - permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); - return true; - case PTChangingEffects_7: - if (sublayer == SubLayer.SetPT_7b) { - permanent.getPower().setModifiedBaseValue(5); - permanent.getToughness().setModifiedBaseValue(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 AbilityAddingRemovingEffects_6: - case PTChangingEffects_7: - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java index 92dcafb438e..08c36ff72a4 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java @@ -1,21 +1,23 @@ package mage.cards.a; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.EntersWithCountersControlledEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; -import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.keyword.*; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; import java.util.UUID; @@ -23,20 +25,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ArlinnThePacksHope extends CardImpl { +public final class ArlinnThePacksHope extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard("creature spells"); public ArlinnThePacksHope(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ARLINN); - this.setStartingLoyalty(4); - this.secondSideCardClazz = mage.cards.a.ArlinnTheMoonsFury.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}", + "Arlinn, the Moon's Fury", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG"); + this.getLeftHalfCard().setStartingLoyalty(4); + this.getRightHalfCard().setStartingLoyalty(4); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); // +1: Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it. Ability ability = new LoyaltyAbility(new CastAsThoughItHadFlashAllEffect( @@ -45,10 +47,23 @@ public final class ArlinnThePacksHope extends CardImpl { ability.addEffect(new EntersWithCountersControlledEffect( StaticFilters.FILTER_PERMANENT_CREATURE, CounterType.P1P1.createInstance(), false ).concatBy(", and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // −3: Create two 2/2 green Wolf creature tokens. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3)); + this.getLeftHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3)); + + // Arlinn, the Moon's Fury + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); + + // +2: Add {R}{G}. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana( + 0, 0, 0, 1, 1, 0, 0, 0 + )), 2)); + + // 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0)); + } private ArlinnThePacksHope(final ArlinnThePacksHope card) { @@ -60,3 +75,66 @@ public final class ArlinnThePacksHope extends CardImpl { return new ArlinnThePacksHope(this); } } + +class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl { + + ArlinnTheMoonsFuryEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste"; + this.dependencyTypes.add(DependencyType.BecomeCreature); + } + + private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) { + super(effect); + } + + @Override + public ArlinnTheMoonsFuryEffect copy() { + return new ArlinnTheMoonsFuryEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + discard(); + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.CREATURE); + permanent.removeAllCreatureTypes(game); + permanent.addSubType(game, SubType.WEREWOLF); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); + permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game); + permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setModifiedBaseValue(5); + permanent.getToughness().setModifiedBaseValue(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 AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArrowStorm.java b/Mage.Sets/src/mage/cards/a/ArrowStorm.java index 7d68830e13d..02c720d83ca 100644 --- a/Mage.Sets/src/mage/cards/a/ArrowStorm.java +++ b/Mage.Sets/src/mage/cards/a/ArrowStorm.java @@ -7,7 +7,6 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; import mage.watchers.common.PlayerAttackedWatcher; @@ -30,7 +29,7 @@ public final class ArrowStorm extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // Raid - If you attacked with a creature this turn, instead Arrow Storm deals 5 damage to that creature or player and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(5, false), + new DamageTargetEffect(5).withCantBePrevented(), RaidCondition.instance, "

Raid — If you attacked this turn, instead {this} deals 5 damage to that permanent or player and the damage can't be prevented")); this.getSpellAbility().addWatcher(new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/a/AshenReaper.java b/Mage.Sets/src/mage/cards/a/AshenReaper.java deleted file mode 100644 index 42bf48228ce..00000000000 --- a/Mage.Sets/src/mage/cards/a/AshenReaper.java +++ /dev/null @@ -1,88 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.WatcherScope; -import mage.counters.CounterType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.watchers.Watcher; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AshenReaper extends CardImpl { - - public AshenReaper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ZOMBIE); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // At the beginning of your end step, put a +1/+1 counter on Ashen Reaper if a permanent was put into a graveyard from the battlefield this turn. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - new ConditionalOneShotEffect( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - AshenReaperCondition.instance, "put a +1/+1 counter on {this} " + - "if a permanent was put into a graveyard from the battlefield this turn" - ) - )); - } - - private AshenReaper(final AshenReaper card) { - super(card); - } - - @Override - public AshenReaper copy() { - return new AshenReaper(this); - } - - public static AshenReaperWatcher makeWatcher() { - return new AshenReaperWatcher(); - } -} - -enum AshenReaperCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return game.getState().getWatcher(AshenReaperWatcher.class).conditionMet(); - } -} - -class AshenReaperWatcher extends Watcher { - - AshenReaperWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ZONE_CHANGE - && ((ZoneChangeEvent) event).isDiesEvent()) { - condition = true; - } - } -} diff --git a/Mage.Sets/src/mage/cards/a/AshlingRekindled.java b/Mage.Sets/src/mage/cards/a/AshlingRekindled.java new file mode 100644 index 00000000000..aa3a0ebf23e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AshlingRekindled.java @@ -0,0 +1,76 @@ +package mage.cards.a; + +import mage.abilities.common.TransformIntoSourceTriggeredAbility; +import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.mana.AddConditionalManaOfAnyColorEffect; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.abilities.meta.OrTriggeredAbility; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ManaValuePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AshlingRekindled extends TransformingDoubleFacedCard { + + private static final FilterSpell filter = new FilterSpell("spells with mana value 4 or greater"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); + } + + public AshlingRekindled(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.SORCERER}, "{1}{R}", + "Ashling, Rimebound", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.WIZARD}, "U" + ); + this.getLeftHalfCard().setPT(1, 3); + this.getRightHalfCard().setPT(1, 3); + + // Whenever this creature enters or transforms into Ashling, Rekindled, you may discard a card. If you do, draw a card. + this.getLeftHalfCard().addAbility(new TransformsOrEntersTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), false + )); + + // At the beginning of your first main phase, you may pay {U}. If you do, transform Ashling. + this.getLeftHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility( + new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{U}")) + )); + + // Ashling, Rimebound + // Whenever this creature transforms into Ashling, Rimebound and at the beginning of your first main phase, add two mana of any one color. Spend this mana only to cast spells with mana value 4 or greater. + this.getRightHalfCard().addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, + new AddConditionalManaOfAnyColorEffect(2, new ConditionalSpellManaBuilder(filter)), + new TransformIntoSourceTriggeredAbility(null), + new BeginningOfFirstMainTriggeredAbility(null) + )); + + // At the beginning of your first main phase, you may pay {R}. If you do, transform Ashling. + this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility( + new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{R}")) + )); + } + + private AshlingRekindled(final AshlingRekindled card) { + super(card); + } + + @Override + public AshlingRekindled copy() { + return new AshlingRekindled(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AshmouthBlade.java b/Mage.Sets/src/mage/cards/a/AshmouthBlade.java deleted file mode 100644 index 4fe8866988e..00000000000 --- a/Mage.Sets/src/mage/cards/a/AshmouthBlade.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.a; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.FirstStrikeAbility; -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 fireshoes - */ -public final class AshmouthBlade extends CardImpl { - - public AshmouthBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.subtype.add(SubType.EQUIPMENT); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Equipped creature gets +3/+3 and has first strike. - Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3)); - ability.addEffect(new GainAbilityAttachedEffect( - FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT - ).setText("and has first strike")); - this.addAbility(ability); - - // Equip {3} - this.addAbility(new EquipAbility(3, false)); - } - - private AshmouthBlade(final AshmouthBlade card) { - super(card); - } - - @Override - public AshmouthBlade copy() { - return new AshmouthBlade(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AshmouthDragon.java b/Mage.Sets/src/mage/cards/a/AshmouthDragon.java deleted file mode 100644 index f4c11eb6b55..00000000000 --- a/Mage.Sets/src/mage/cards/a/AshmouthDragon.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.DamageTargetEffect; -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 mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AshmouthDragon extends CardImpl { - - public AshmouthDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever you cast an instant or sorcery spell, Ashmouth Dragon deals 2 damage to any target. - Ability ability = new SpellCastControllerTriggeredAbility( - new DamageTargetEffect(2), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false - ); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - } - - private AshmouthDragon(final AshmouthDragon card) { - super(card); - } - - @Override - public AshmouthDragon copy() { - return new AshmouthDragon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AshmouthHound.java b/Mage.Sets/src/mage/cards/a/AshmouthHound.java index 4fcfac4c2ab..5e9241b9555 100644 --- a/Mage.Sets/src/mage/cards/a/AshmouthHound.java +++ b/Mage.Sets/src/mage/cards/a/AshmouthHound.java @@ -23,7 +23,7 @@ public final class AshmouthHound extends CardImpl { this.toughness = new MageInt(1); // Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"))); } private AshmouthHound(final AshmouthHound card) { diff --git a/Mage.Sets/src/mage/cards/a/AssembledAlphas.java b/Mage.Sets/src/mage/cards/a/AssembledAlphas.java index dd5ca0e07cf..fbb15e6b892 100644 --- a/Mage.Sets/src/mage/cards/a/AssembledAlphas.java +++ b/Mage.Sets/src/mage/cards/a/AssembledAlphas.java @@ -1,16 +1,14 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksOrBlockedByCreatureSourceTriggeredAbility; -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; + +import java.util.UUID; /** * @@ -25,9 +23,8 @@ public final class AssembledAlphas extends CardImpl { this.toughness = new MageInt(5); // Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller. - Ability ability = new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(3, true, "that creature")); - ability.addEffect(new DamageTargetControllerEffect(3).setText("and 3 damage to that creature's controller")); - this.addAbility(ability); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( + new DamageTargetAndTargetControllerEffect(3, 3))); } private AssembledAlphas(final AssembledAlphas card) { diff --git a/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java b/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java index 44e0980ea2d..6a9fea9455f 100644 --- a/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java +++ b/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java @@ -10,14 +10,10 @@ import mage.abilities.dynamicvalue.common.CountersControllerCount; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect; -import mage.abilities.keyword.PartnerFatherAndSonAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.constants.*; import mage.counters.CounterType; import java.util.UUID; @@ -50,7 +46,7 @@ public final class AtreusImpulsiveSon extends CardImpl { this.addAbility(ability); // Partner--Father & son - this.addAbility(PartnerFatherAndSonAbility.getInstance()); + this.addAbility(PartnerVariantType.FATHER_AND_SON.makeAbility()); } private AtreusImpulsiveSon(final AtreusImpulsiveSon card) { diff --git a/Mage.Sets/src/mage/cards/a/AttumaAtlanteanWarlord.java b/Mage.Sets/src/mage/cards/a/AttumaAtlanteanWarlord.java new file mode 100644 index 00000000000..d5e001f324e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AttumaAtlanteanWarlord.java @@ -0,0 +1,51 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AttumaAtlanteanWarlord extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.MERFOLK); + + public AttumaAtlanteanWarlord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Other Merfolk you control get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + ))); + + // Whenever one or more Merfolk you control attack a player, draw a card. + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, SetTargetPointer.NONE + )); + } + + private AttumaAtlanteanWarlord(final AttumaAtlanteanWarlord card) { + super(card); + } + + @Override + public AttumaAtlanteanWarlord copy() { + return new AttumaAtlanteanWarlord(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java b/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java deleted file mode 100644 index 73362456eba..00000000000 --- a/Mage.Sets/src/mage/cards/a/AtzalCaveOfEternity.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.a; - -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.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.target.common.TargetCardInYourGraveyard; - -/** - * - * @author LevelX2 - */ -public final class AtzalCaveOfEternity extends CardImpl { - - public AtzalCaveOfEternity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // (Transforms from Journey to Eternity.) - - // {t}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - - // {3}{B}{G}, {T}: Return target creature card from your graveyard to the battlefield. - Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{3}{B}{G}")); - ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.addAbility(ability); - } - - private AtzalCaveOfEternity(final AtzalCaveOfEternity card) { - super(card); - } - - @Override - public AtzalCaveOfEternity copy() { - return new AtzalCaveOfEternity(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java b/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java deleted file mode 100644 index 0ed7789746d..00000000000 --- a/Mage.Sets/src/mage/cards/a/AuroraOfEmrakul.java +++ /dev/null @@ -1,49 +0,0 @@ - -package mage.cards.a; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; -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.SubType; - -/** - * - * @author fireshoes - */ -public final class AuroraOfEmrakul extends CardImpl { - - public AuroraOfEmrakul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.REFLECTION); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Aurora of Emrakul attacks, each opponent loses 3 life. - this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(3),false)); - } - - private AuroraOfEmrakul(final AuroraOfEmrakul card) { - super(card); - } - - @Override - public AuroraOfEmrakul copy() { - return new AuroraOfEmrakul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java index b7d0f232ddf..cb36799b9bc 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java +++ b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java @@ -6,12 +6,14 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import java.util.UUID; @@ -19,20 +21,28 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class AutumnalGloom extends CardImpl { +public final class AutumnalGloom extends TransformingDoubleFacedCard { public AutumnalGloom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); - this.secondSideCardClazz = mage.cards.a.AncientOfTheEquinox.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{G}", + "Ancient of the Equinox", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK}, "G"); + this.getRightHalfCard().setPT(4, 4); // {B}: Put the top card of your library into your graveyard. - this.addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}"))); // Delirium — At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new TransformSourceEffect(), false, DeliriumCondition.instance ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + + // Ancient of the Equinox + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); } private AutumnalGloom(final AutumnalGloom card) { diff --git a/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java b/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java index eaec30e14aa..56cd948b985 100644 --- a/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java +++ b/Mage.Sets/src/mage/cards/a/AvabruckCaretaker.java @@ -1,14 +1,18 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -19,29 +23,49 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class AvabruckCaretaker extends CardImpl { +public final class AvabruckCaretaker extends TransformingDoubleFacedCard { public AvabruckCaretaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.h.HollowhengeHuntmaster.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}{G}", + "Hollowhenge Huntmaster", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 6); // Hexproof - this.addAbility(HexproofAbility.getInstance()); + this.getLeftHalfCard().addAbility(HexproofAbility.getInstance()); // At the beginning of combat on your turn, put two +1/+1 counters on another target creature you control. Ability ability = new BeginningOfCombatTriggeredAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Hollowhenge Huntmaster + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); + + // Other permanents you control have hexproof. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENTS, true + ))); + + // At the beginning of combat on your turn, put two +1/+1 counters on each creature you control. + this.getRightHalfCard().addAbility(new BeginningOfCombatTriggeredAbility( + new AddCountersAllEffect( + CounterType.P1P1.createInstance(2), + StaticFilters.FILTER_CONTROLLED_CREATURE + ) + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private AvabruckCaretaker(final AvabruckCaretaker card) { diff --git a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java b/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java deleted file mode 100644 index fc2d87749c9..00000000000 --- a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.DamageAllEffect; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.keyword.FlyingAbility; -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.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class AvacynThePurifier extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent("other creature"); - - static { - filter.add(AnotherPredicate.instance); - } - - public AvacynThePurifier(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. - Ability ability = new TransformIntoSourceTriggeredAbility( - new DamageAllEffect(3, "it", filter) - ); - ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent")); - this.addAbility(ability); - } - - private AvacynThePurifier(final AvacynThePurifier card) { - super(card); - } - - @Override - public AvacynThePurifier copy() { - return new AvacynThePurifier(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java b/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java index 400732c969f..e0aa0fdc661 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java +++ b/Mage.Sets/src/mage/cards/a/AvacynianMissionaries.java @@ -1,37 +1,43 @@ package mage.cards.a; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.common.EquippedSourceCondition; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; /** * @author fireshoes */ -public final class AvacynianMissionaries extends CardImpl { +public final class AvacynianMissionaries extends TransformingDoubleFacedCard { public AvacynianMissionaries(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.l.LunarchInquisitors.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{3}{W}", + "Lunarch Inquisitors", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "W"); + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // At the beginning of your end step, if Avacynian Missionaries is equipped, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"), + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"), false, EquippedSourceCondition.instance)); + // Lunarch Inquisitors + // When this creature transforms into Lunarch Inquisitors, you may exile another target creature until Lunarch Inquisitors leaves the battlefield. + Ability ability = new TransformIntoSourceTriggeredAbility(new ExileUntilSourceLeavesEffect(), true); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.getRightHalfCard().addAbility(ability); } private AvacynianMissionaries(final AvacynianMissionaries card) { diff --git a/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java b/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java index 6ef053cc5c2..911a52fe8da 100644 --- a/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java +++ b/Mage.Sets/src/mage/cards/a/AvalancheOfSector7.java @@ -65,7 +65,7 @@ public final class AvalancheOfSector7 extends CardImpl { class AvalancheOfSector7TriggeredAbility extends TriggeredAbilityImpl { AvalancheOfSector7TriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); setTriggerPhrase("Whenever an opponent activates an ability of an artifact they control, "); } diff --git a/Mage.Sets/src/mage/cards/a/AvatarAang.java b/Mage.Sets/src/mage/cards/a/AvatarAang.java index 24be5ad614e..71ddf626fc6 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarAang.java +++ b/Mage.Sets/src/mage/cards/a/AvatarAang.java @@ -1,50 +1,80 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FirebendingAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import java.util.UUID; /** * @author TheElk801 */ -public final class AvatarAang extends CardImpl { +public final class AvatarAang extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("spells"); public AvatarAang(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{R}{G}{W}{U}", + "Aang, Master of Elements", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.ALLY); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.a.AangMasterOfElements.class; + this.getLeftHalfCard().setPT(4, 4); + this.getRightHalfCard().setPT(6, 6); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Firebending 2 - this.addAbility(new FirebendingAbility(2)); + this.getLeftHalfCard().addAbility(new FirebendingAbility(2)); // Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang. - this.addAbility(new AvatarAangTriggeredAbility()); + this.getLeftHalfCard().addAbility(new AvatarAangTriggeredAbility()); + + // Aang, Master of Elements + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Spells you cast cost {W}{U}{B}{R}{G} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( + filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true + ))); + + // At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( + TargetController.ANY, + new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost()) + .addEffect(new DrawCardSourceControllerEffect(4).concatBy(",")) + .addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)) + .setText(", put four +1/+1 counters on him")) + .addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT) + .setText(", and he deals 4 damage to each opponent")), + false + )); } private AvatarAang(final AvatarAang card) { @@ -154,3 +184,37 @@ class AvatarAangWatcher extends Watcher { return game.getState().getWatcher(AvatarAangWatcher.class).checkPlayer(source.getControllerId()); } } + +class AangMasterOfElementsCost extends CostImpl { + + AangMasterOfElementsCost() { + super(); + text = "transform {this}"; + } + + private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) { + super(cost); + } + + @Override + public AangMasterOfElementsCost copy() { + return new AangMasterOfElementsCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .filter(Card::isTransformable) + .isPresent(); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + paid = Optional + .ofNullable(source.getSourcePermanentIfItStillExists(game)) + .filter(permanent -> permanent.transform(source, game)) + .isPresent(); + return paid; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarDestiny.java b/Mage.Sets/src/mage/cards/a/AvatarDestiny.java new file mode 100644 index 00000000000..c3e3e34b5bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarDestiny.java @@ -0,0 +1,110 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.constants.*; +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.TargetControlledCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarDestiny extends CardImpl { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE); + + public AvatarDestiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature gets +1/+1 for each creature card in your graveyard and is an Avatar in addition to its other types. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue)); + ability.addEffect(new AddCardSubtypeAttachedEffect( + SubType.AVATAR, AttachmentType.AURA + ).setText("and is an Avatar in addition to its other types")); + this.addAbility(ability); + + // When enchanted creature dies, mill cards equal to its power. Return this card to its owner's hand and up to one creature card milled this way to the battlefield under your control. + this.addAbility(new DiesAttachedTriggeredAbility(new AvatarDestinyEffect(), "enchanted creature")); + } + + private AvatarDestiny(final AvatarDestiny card) { + super(card); + } + + @Override + public AvatarDestiny copy() { + return new AvatarDestiny(this); + } +} + +class AvatarDestinyEffect extends OneShotEffect { + + AvatarDestinyEffect() { + super(Outcome.Benefit); + staticText = "mill cards equal to its power. Return this card to its owner's hand and up to one " + + "creature card milled this way to the battlefield under your control"; + } + + private AvatarDestinyEffect(final AvatarDestinyEffect effect) { + super(effect); + } + + @Override + public AvatarDestinyEffect copy() { + return new AvatarDestinyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = Optional + .ofNullable((Permanent) getValue("attachedTo")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + Cards cards = player.millCards(count, source, game); + game.processAction(); + new ReturnToHandSourceEffect(false, true).apply(game, source); + TargetCard target = new TargetCard(0, 1, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE); + target.withNotTarget(true); + player.choose(Outcome.PutCreatureInPlay, cards, target, source, game); + player.moveCards( + game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source, + game, true, false, false, null + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java b/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java new file mode 100644 index 00000000000..69f20bef3cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarKyoshiEarthbender.java @@ -0,0 +1,58 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +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.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarKyoshiEarthbender extends CardImpl { + + public AvatarKyoshiEarthbender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // During your turn, Avatar Kyoshi has hexproof. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield), + MyTurnCondition.instance, "during your turn, {this} has hexproof" + ))); + + // At the beginning of combat on your turn, earthbend 8, then untap that land. + Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(8, false)); + ability.addEffect(new UntapTargetEffect().setText(", then untap that land")); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private AvatarKyoshiEarthbender(final AvatarKyoshiEarthbender card) { + super(card); + } + + @Override + public AvatarKyoshiEarthbender copy() { + return new AvatarKyoshiEarthbender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarRokuFirebender.java b/Mage.Sets/src/mage/cards/a/AvatarRokuFirebender.java new file mode 100644 index 00000000000..00c7e62e87b --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarRokuFirebender.java @@ -0,0 +1,108 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarRokuFirebender extends CardImpl { + + public AvatarRokuFirebender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Whenever a player attacks, add six {R}. Until end of combat, you don't lose this mana as steps end. + this.addAbility(new AvatarRokuFirebenderTriggeredAbility()); + + // {R}{R}{R}: Target creature gets +3/+0 until end of turn. + Ability ability = new SimpleActivatedAbility( + new BoostTargetEffect(3, 0), new ManaCostsImpl<>("{R}{R}{R}") + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private AvatarRokuFirebender(final AvatarRokuFirebender card) { + super(card); + } + + @Override + public AvatarRokuFirebender copy() { + return new AvatarRokuFirebender(this); + } +} + +class AvatarRokuFirebenderTriggeredAbility extends TriggeredAbilityImpl { + + AvatarRokuFirebenderTriggeredAbility() { + super(Zone.BATTLEFIELD, new AvatarRokuFirebenderEffect()); + setTriggerPhrase("Whenever a player attacks, "); + } + + private AvatarRokuFirebenderTriggeredAbility(final AvatarRokuFirebenderTriggeredAbility ability) { + super(ability); + } + + @Override + public AvatarRokuFirebenderTriggeredAbility copy() { + return new AvatarRokuFirebenderTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return !game.getCombat().getAttackers().isEmpty(); + } +} + +class AvatarRokuFirebenderEffect extends OneShotEffect { + + AvatarRokuFirebenderEffect() { + super(Outcome.Benefit); + staticText = "add six {R}. Until end of combat, you don't lose this mana as steps end"; + } + + private AvatarRokuFirebenderEffect(final AvatarRokuFirebenderEffect effect) { + super(effect); + } + + @Override + public AvatarRokuFirebenderEffect copy() { + return new AvatarRokuFirebenderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.getManaPool().addMana(Mana.RedMana(6), game, source, Duration.EndOfCombat); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarsWrath.java b/Mage.Sets/src/mage/cards/a/AvatarsWrath.java new file mode 100644 index 00000000000..164e1700fcb --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarsWrath.java @@ -0,0 +1,114 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +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.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 java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvatarsWrath extends CardImpl { + + public AvatarsWrath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); + + // Choose up to one target creature, then airbend all other creatures. + this.getSpellAbility().addEffect(new AvatarsWrathAirbendEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + + // Until your next turn, your opponents can't cast spells from anywhere other than their hand. + this.getSpellAbility().addEffect(new AvatarsWrathRuleEffect()); + + // Exile Avatar's Wrath. + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); + } + + private AvatarsWrath(final AvatarsWrath card) { + super(card); + } + + @Override + public AvatarsWrath copy() { + return new AvatarsWrath(this); + } +} + +class AvatarsWrathAirbendEffect extends OneShotEffect { + + AvatarsWrathAirbendEffect() { + super(Outcome.Benefit); + staticText = "choose up to one target creature, then airbend all other creatures"; + } + + private AvatarsWrathAirbendEffect(final AvatarsWrathAirbendEffect effect) { + super(effect); + } + + @Override + public AvatarsWrathAirbendEffect copy() { + return new AvatarsWrathAirbendEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); + Optional.ofNullable(game.getPermanent(getTargetPointer().getFirst(game, source))) + .ifPresent(permanents::remove); + return !permanents.isEmpty() + && new AirbendTargetEffect() + .setTargetPointer(new FixedTargets(permanents, game)) + .apply(game, source); + } +} + +class AvatarsWrathRuleEffect extends ContinuousRuleModifyingEffectImpl { + + AvatarsWrathRuleEffect() { + super(Duration.UntilYourNextTurn, Outcome.Benefit); + staticText = "
Until your next turn, your opponents can't cast spells from anywhere other than their hand."; + } + + private AvatarsWrathRuleEffect(final AvatarsWrathRuleEffect effect) { + super(effect); + } + + @Override + public AvatarsWrathRuleEffect copy() { + return new AvatarsWrathRuleEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; + } + Card card = game.getCard(event.getSourceId()); + return card != null && game.getState().getZone(card.getId()) != Zone.HAND; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AwakenTheMaelstrom.java b/Mage.Sets/src/mage/cards/a/AwakenTheMaelstrom.java deleted file mode 100644 index ff4ba76a560..00000000000 --- a/Mage.Sets/src/mage/cards/a/AwakenTheMaelstrom.java +++ /dev/null @@ -1,128 +0,0 @@ -package mage.cards.a; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.*; -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.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanentAmount; -import mage.target.common.TargetPermanentAmount; -import mage.target.targetpointer.SecondTargetPointer; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AwakenTheMaelstrom extends CardImpl { - - public AwakenTheMaelstrom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); - - this.nightCard = true; - - // Awaken the Maelstrom 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(Zone.ALL, new InfoEffect("{this} is all colors"))); - - // Target player draws two cards. - this.getSpellAbility().addEffect(new DrawCardTargetEffect(2)); - this.getSpellAbility().addTarget(new TargetPlayer().withChooseHint("to draw two cards")); - - // You may put an artifact card from your hand onto the battlefield. - this.getSpellAbility().addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_ARTIFACT_AN)); - - // Create a token that's a copy of a permanent you control. - // Distribute three +1/+1 counters among one, two, or three creatures you control. - this.getSpellAbility().addEffect(new AwakenTheMaelstromEffect()); - - // Destroy target permanent an opponent controls. - this.getSpellAbility().addEffect(new DestroyTargetEffect().setTargetPointer(new SecondTargetPointer())); - this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT).withChooseHint("to destroy")); - } - - private AwakenTheMaelstrom(final AwakenTheMaelstrom card) { - super(card); - } - - @Override - public AwakenTheMaelstrom copy() { - return new AwakenTheMaelstrom(this); - } -} - -class AwakenTheMaelstromEffect extends OneShotEffect { - - AwakenTheMaelstromEffect() { - super(Outcome.Benefit); - staticText = "Create a token that's a copy of a permanent you control. " + - "Distribute three +1/+1 counters among one, two, or three creatures you control."; - } - - private AwakenTheMaelstromEffect(final AwakenTheMaelstromEffect effect) { - super(effect); - } - - @Override - public AwakenTheMaelstromEffect copy() { - return new AwakenTheMaelstromEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - makeToken(player, game, source); - game.processAction(); - distributeCounters(player, game, source); - return true; - } - - private void makeToken(Player player, Game game, Ability source) { - TargetPermanent target = new TargetControlledCreaturePermanent(); - target.withNotTarget(true); - target.withChooseHint("to copy"); - if (!target.canChoose(player.getId(), source, game)) { - return; - } - player.choose(outcome, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - new CreateTokenCopyTargetEffect().setSavedPermanent(permanent).apply(game, source); - } - } - - private void distributeCounters(Player player, Game game, Ability source) { - if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game) < 1) { - return; - } - TargetPermanentAmount target = new TargetCreaturePermanentAmount(3, StaticFilters.FILTER_CONTROLLED_CREATURE); - target.withNotTarget(true); - target.withChooseHint("to distribute counters"); - target.chooseTarget(outcome, player.getId(), 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); - } - } - } -} diff --git a/Mage.Sets/src/mage/cards/a/AwakenedSkyclave.java b/Mage.Sets/src/mage/cards/a/AwakenedSkyclave.java deleted file mode 100644 index 48e9a24dee8..00000000000 --- a/Mage.Sets/src/mage/cards/a/AwakenedSkyclave.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.abilities.mana.AnyColorManaAbility; -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 AwakenedSkyclave extends CardImpl { - - public AwakenedSkyclave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // As long as Awakened Skyclave is on the battlefield, it's a land in addition to its other types. - this.addAbility(new SimpleStaticAbility(new AddCardTypeSourceEffect(Duration.WhileOnBattlefield, CardType.LAND) - .setText("as long as {this} is on the battlefield, it's a land in addition to its other types"))); - - // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - } - - private AwakenedSkyclave(final AwakenedSkyclave card) { - super(card); - } - - @Override - public AwakenedSkyclave copy() { - return new AwakenedSkyclave(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AweStrike.java b/Mage.Sets/src/mage/cards/a/AweStrike.java index fd3e498d7c9..232bda5b053 100755 --- a/Mage.Sets/src/mage/cards/a/AweStrike.java +++ b/Mage.Sets/src/mage/cards/a/AweStrike.java @@ -57,14 +57,13 @@ class AweStrikeEffect extends PreventionEffectImpl { if (player != null) { player.gainLife(preventionData.getPreventedDamage(), game, source); } - this.used = true; this.discard(); - return true; + return false; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { + if (super.applies(event, source, game)) { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); return targetCreature != null && targetCreature.getId().equals(event.getSourceId()); } diff --git a/Mage.Sets/src/mage/cards/a/AwokenDemon.java b/Mage.Sets/src/mage/cards/a/AwokenDemon.java deleted file mode 100644 index dabf328e6ce..00000000000 --- a/Mage.Sets/src/mage/cards/a/AwokenDemon.java +++ /dev/null @@ -1,34 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -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 AwokenDemon extends CardImpl { - - public AwokenDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DEMON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - } - - private AwokenDemon(final AwokenDemon card) { - super(card); - } - - @Override - public AwokenDemon copy() { - return new AwokenDemon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AwokenHorror.java b/Mage.Sets/src/mage/cards/a/AwokenHorror.java deleted file mode 100644 index 1fab7bc271c..00000000000 --- a/Mage.Sets/src/mage/cards/a/AwokenHorror.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; -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.Predicates; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class AwokenHorror extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Horror creatures"); - - static { - filter.add(Predicates.not(SubType.HORROR.getPredicate())); - } - - public AwokenHorror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.KRAKEN); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(7); - this.toughness = new MageInt(8); - this.color.setBlue(true); - - this.nightCard = true; - - // When this creature transforms into Awoken Horrow, return all non-Horror creatures to their owners' hands. - this.addAbility(new TransformIntoSourceTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter))); - } - - private AwokenHorror(final AwokenHorror card) { - super(card); - } - - @Override - public AwokenHorror copy() { - return new AwokenHorror(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java b/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java deleted file mode 100644 index 686133de413..00000000000 --- a/Mage.Sets/src/mage/cards/a/AyaraFurnaceQueen.java +++ /dev/null @@ -1,109 +0,0 @@ -package mage.cards.a; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; -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.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class AyaraFurnaceQueen extends CardImpl { - - private static final FilterCard filter = new FilterCard("artifact or creature card from your graveyard"); - - static { - filter.add(Predicates.or( - CardType.ARTIFACT.getPredicate(), - CardType.CREATURE.getPredicate() - )); - } - - public AyaraFurnaceQueen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - // At the beginning of combat on your turn, return up to one target artifact or creature card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. - Ability ability = new BeginningOfCombatTriggeredAbility( - new AyaraFurnaceQueenEffect() - ); - ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter)); - this.addAbility(ability); - } - - private AyaraFurnaceQueen(final AyaraFurnaceQueen card) { - super(card); - } - - @Override - public AyaraFurnaceQueen copy() { - return new AyaraFurnaceQueen(this); - } -} - -class AyaraFurnaceQueenEffect extends OneShotEffect { - - AyaraFurnaceQueenEffect() { - super(Outcome.Benefit); - staticText = "return up to one target artifact or creature card from your graveyard " + - "to the battlefield. It gains haste. Exile it at the beginning of the next end step"; - } - - private AyaraFurnaceQueenEffect(final AyaraFurnaceQueenEffect effect) { - super(effect); - } - - @Override - public AyaraFurnaceQueenEffect copy() { - return new AyaraFurnaceQueenEffect(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; - } - Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); - if (permanent == null) { - return false; - } - game.addEffect(new GainAbilityTargetEffect( - HasteAbility.getInstance(), Duration.Custom - ).setTargetPointer(new FixedTarget(permanent.getId(), game)), source); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( - new ExileTargetEffect().setText("exile it") - .setTargetPointer(new FixedTarget(permanent.getId(), game)), - TargetController.ANY - ), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java b/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java index 5fa76e7bcb9..84ca40120a5 100644 --- a/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java +++ b/Mage.Sets/src/mage/cards/a/AyaraWidowOfTheRealm.java @@ -1,49 +1,66 @@ package mage.cards.a; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; 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.SacrificeCostManaValue; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.FilterOpponent; import mage.filter.StaticFilters; import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetPermanentOrPlayer; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.UUID; /** * @author TheElk801 */ -public final class AyaraWidowOfTheRealm extends CardImpl { +public final class AyaraWidowOfTheRealm extends TransformingDoubleFacedCard { private static final DynamicValue xValue = SacrificeCostManaValue.PERMANENT; private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer( "opponent or battle", StaticFilters.FILTER_PERMANENT_BATTLE, new FilterOpponent() ); + private static final FilterCard furnaceQueenFilter = new FilterCard("artifact or creature card from your graveyard"); + + static { + furnaceQueenFilter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); + } public AyaraWidowOfTheRealm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AyaraFurnaceQueen.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELF, SubType.NOBLE}, "{1}{B}{B}", + "Ayara, Furnace Queen", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ELF, SubType.NOBLE}, "BR"); + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // {T}, Sacrifice another creature or artifact: Ayara, Widow of the Realm deals X damage to target opponent or battle and you gain X life, where X is the sacrificed permanent's mana value. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(xValue) @@ -51,11 +68,18 @@ public final class AyaraWidowOfTheRealm extends CardImpl { ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT)); ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the sacrificed permanent's mana value")); ability.addTarget(new TargetPermanentOrPlayer(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {5}{R/P}: Transform Ayara. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + + // Ayara, Furnace Queen + // At the beginning of combat on your turn, return up to one target artifact or creature card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. + Ability triggeredAbility = new BeginningOfCombatTriggeredAbility( + new AyaraFurnaceQueenEffect() + ); + triggeredAbility.addTarget(new TargetCardInYourGraveyard(0, 1, furnaceQueenFilter)); + this.getRightHalfCard().addAbility(triggeredAbility); } private AyaraWidowOfTheRealm(final AyaraWidowOfTheRealm card) { @@ -67,3 +91,43 @@ public final class AyaraWidowOfTheRealm extends CardImpl { return new AyaraWidowOfTheRealm(this); } } + +class AyaraFurnaceQueenEffect extends OneShotEffect { + + AyaraFurnaceQueenEffect() { + super(Outcome.Benefit); + staticText = "return up to one target artifact or creature card from your graveyard " + + "to the battlefield. It gains haste. Exile it at the beginning of the next end step"; + } + + private AyaraFurnaceQueenEffect(final AyaraFurnaceQueenEffect effect) { + super(effect); + } + + @Override + public AyaraFurnaceQueenEffect copy() { + return new AyaraFurnaceQueenEffect(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; + } + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent == null) { + return false; + } + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.Custom + ).setTargetPointer(new FixedTarget(permanent.getId(), game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ExileTargetEffect().setText("exile it") + .setTargetPointer(new FixedTarget(permanent.getId(), game)), + TargetController.ANY + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java b/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java deleted file mode 100644 index 9be6a546534..00000000000 --- a/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.a; - -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.LookLibraryAndPickControllerEffect; -import mage.abilities.mana.BlueManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SuperType; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; - -/** - * - * @author LevelX2 - */ -public final class AzcantaTheSunkenRuin extends CardImpl { - - private static final FilterCard filter = new FilterCard("a noncreature, nonland card"); - - static { - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - } - - public AzcantaTheSunkenRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - // this card is the second face of double-faced card - this.nightCard = true; - - // (Transforms from Search for Azcanta)/ - // {T} : Add {U}. - this.addAbility(new BlueManaAbility()); - - // {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( - new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY), - new ManaCostsImpl<>("{2}{U}") - ); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private AzcantaTheSunkenRuin(final AzcantaTheSunkenRuin card) { - super(card); - } - - @Override - public AzcantaTheSunkenRuin copy() { - return new AzcantaTheSunkenRuin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AzorsElocutors.java b/Mage.Sets/src/mage/cards/a/AzorsElocutors.java index 633d1c6f776..302d55090ac 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsElocutors.java +++ b/Mage.Sets/src/mage/cards/a/AzorsElocutors.java @@ -44,6 +44,7 @@ public final class AzorsElocutors extends CardImpl { new WinGameSourceControllerEffect(), condition, "Then if {this} has five or more filibuster counters on it, you win the game" )); + this.addAbility(ability); // Whenever a source deals damage to you, remove a filibuster counter from Azor's Elocutors. this.addAbility(new AzorsElocutorsTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/a/AzorsGateway.java b/Mage.Sets/src/mage/cards/a/AzorsGateway.java index 4a6f94a4a39..8e86cef827c 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsGateway.java +++ b/Mage.Sets/src/mage/cards/a/AzorsGateway.java @@ -1,23 +1,26 @@ package mage.cards.a; import mage.MageObject; +import mage.Mana; import mage.abilities.Ability; 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.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.game.ExileZone; import mage.game.Game; @@ -31,18 +34,17 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class AzorsGateway extends CardImpl { +public final class AzorsGateway extends TransformingDoubleFacedCard { public AzorsGateway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.s.SanctumOfTheSun.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "Sanctum of the Sun", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); // {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(new DrawCardSourceControllerEffect(1), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addEffect(new AzorsGatewayEffect()); @@ -50,7 +52,13 @@ public final class AzorsGateway extends CardImpl { new GainLifeEffect(5), AzorsGatewayCondition.instance, "If cards with five or more " + "different mana values are exiled with {this}, you gain 5 life, untap {this}, and transform it." ).addEffect(new UntapSourceEffect()).addEffect(new TransformSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Sanctum of the Sun + // {T}: Add X mana of any one color, where X is your life total. + this.getRightHalfCard().addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), ControllerLifeCount.instance, new TapSourceCost(), + "Add X mana of any one color, where X is your life total", true)); + } private AzorsGateway(final AzorsGateway card) { diff --git a/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java b/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java new file mode 100644 index 00000000000..2efc85c5dc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzulaCunningUsurper.java @@ -0,0 +1,218 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +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.abilities.keyword.FirebendingAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AzulaCunningUsurper extends CardImpl { + + public AzulaCunningUsurper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // When Azula enters, target opponent exiles a nontoken creature they control, then they exile a nonland card from their graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new AzulaCunningUsurperExileEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // During your turn, you may cast cards exiled with Azula and you may cast them as though they had flash. Mana of any type can be spent to cast those spells. + ability = new SimpleStaticAbility(new AzulaCunningUsurperCastEffect()); + ability.addEffect(new AzulaCunningUsurperFlashEffect()); + ability.addEffect(new AzulaCunningUsurperManaEffect()); + this.addAbility(ability); + } + + private AzulaCunningUsurper(final AzulaCunningUsurper card) { + super(card); + } + + @Override + public AzulaCunningUsurper copy() { + return new AzulaCunningUsurper(this); + } +} + +class AzulaCunningUsurperExileEffect extends OneShotEffect { + + AzulaCunningUsurperExileEffect() { + super(Outcome.Benefit); + staticText = "target opponent exiles a nontoken creature they control, " + + "then they exile a nonland card from their graveyard"; + } + + private AzulaCunningUsurperExileEffect(final AzulaCunningUsurperExileEffect effect) { + super(effect); + } + + @Override + public AzulaCunningUsurperExileEffect copy() { + return new AzulaCunningUsurperExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + if (game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, player.getId(), source, game, 1)) { + TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN); + target.withNotTarget(true); + player.choose(Outcome.Exile, target, source, game); + cards.add(target.getFirstTarget()); + } + if (player.getGraveyard().count(StaticFilters.FILTER_CARD_A_NON_CREATURE, game) > 0) { + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_A_NON_CREATURE); + target.withNotTarget(true); + player.choose(Outcome.Exile, target, source, game); + cards.add(target.getFirstTarget()); + } + return player.moveCardsToExile( + cards.getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceLogName(game, source) + ); + } +} + +class AzulaCunningUsurperCastEffect extends AsThoughEffectImpl { + + AzulaCunningUsurperCastEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "during your turn, you may cast cards exiled with {this}"; + } + + private AzulaCunningUsurperCastEffect(final AzulaCunningUsurperCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperCastEffect copy() { + return new AzulaCunningUsurperCastEffect(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); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } +} + +class AzulaCunningUsurperFlashEffect extends AsThoughEffectImpl { + + AzulaCunningUsurperFlashEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "and you may cast them as though they had flash"; + } + + private AzulaCunningUsurperFlashEffect(final AzulaCunningUsurperFlashEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperFlashEffect copy() { + return new AzulaCunningUsurperFlashEffect(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); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } +} + +class AzulaCunningUsurperManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + AzulaCunningUsurperManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Mana of any type can be spent to cast those spells"; + } + + private AzulaCunningUsurperManaEffect(final AzulaCunningUsurperManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AzulaCunningUsurperManaEffect copy() { + return new AzulaCunningUsurperManaEffect(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); + if (card == null || card.isLand(game)) { + return false; + } + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && exileZone.contains(objectId); + } + + @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/a/AzulaOnTheHunt.java b/Mage.Sets/src/mage/cards/a/AzulaOnTheHunt.java new file mode 100644 index 00000000000..ab9ae91c5ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzulaOnTheHunt.java @@ -0,0 +1,49 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.keyword.FirebendingAbility; +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.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AzulaOnTheHunt extends CardImpl { + + public AzulaOnTheHunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // Whenever Azula attacks, you lose 1 life and create a Clue token. + Ability ability = new AttacksTriggeredAbility(new LoseLifeSourceControllerEffect(1)); + ability.addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("and")); + this.addAbility(ability); + } + + private AzulaOnTheHunt(final AzulaOnTheHunt card) { + super(card); + } + + @Override + public AzulaOnTheHunt copy() { + return new AzulaOnTheHunt(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzulaRuthlessFirebender.java b/Mage.Sets/src/mage/cards/a/AzulaRuthlessFirebender.java new file mode 100644 index 00000000000..13749759c0e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzulaRuthlessFirebender.java @@ -0,0 +1,93 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.OptionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourceControllerCountersCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersPlayersEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.constants.*; +import mage.abilities.keyword.FirebendingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.counters.CounterType; +import mage.game.Game; +import mage.watchers.common.DiscardedCardWatcher; + +/** + * + * @author anonymous + */ +public final class AzulaRuthlessFirebender extends CardImpl { + + public AzulaRuthlessFirebender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // Whenever Azula attacks, you may discard a card. Then you get an experience counter for each player who discarded a card this turn. + Ability ability = new AttacksTriggeredAbility(new OptionalOneShotEffect(new DiscardControllerEffect(1))); + ability.addEffect(new AddCountersPlayersEffect(CounterType.EXPERIENCE.createInstance(), AzulaRuthlessFirebenderValue.instance, TargetController.YOU).setText("Then you get an experience counter for each player who discarded a card this turn.")); + this.addAbility(ability, new DiscardedCardWatcher()); + + // {2}{B}: Until end of turn, Azula gets +1/+1 for each experience counter you have and gains menace. + ability = new SimpleActivatedAbility(new BoostSourceEffect(SourceControllerCountersCount.EXPERIENCE, SourceControllerCountersCount.EXPERIENCE, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{B}")); + ability.addEffect(new GainAbilitySourceEffect(new MenaceAbility(), Duration.EndOfTurn).setText("and gains menace")); + this.addAbility(ability); + } + + private AzulaRuthlessFirebender(final AzulaRuthlessFirebender card) { + super(card); + } + + @Override + public AzulaRuthlessFirebender copy() { + return new AzulaRuthlessFirebender(this); + } +} + +enum AzulaRuthlessFirebenderValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int playersDiscardedThisTurn = 0; + for (UUID playerId : game.getState().getPlayersInRange(sourceAbility.getControllerId(), game)) { + if (DiscardedCardWatcher.checkPlayerDiscarded(playerId, game)) { + playersDiscardedThisTurn += 1; + } + } + return playersDiscardedThisTurn; + } + + @Override + public AzulaRuthlessFirebenderValue copy() { + return this; + } + + @Override + public String getMessage() { + return "for each player who discarded a card this turn"; + } + + @Override + public String toString() { + return "X"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java b/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java index b62d3daf6f5..1f240eb0840 100644 --- a/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java +++ b/Mage.Sets/src/mage/cards/a/AzusasManyJourneys.java @@ -1,45 +1,51 @@ package mage.cards.a; -import java.util.UUID; - +import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.UntapLandsEffect; import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect; -import mage.abilities.keyword.TransformAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; + +import java.util.UUID; /** * * @author weirddan455 */ -public final class AzusasManyJourneys extends CardImpl { +public final class AzusasManyJourneys extends TransformingDoubleFacedCard { public AzusasManyJourneys(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{G}", + "Likeness of the Seeker", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "G"); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.l.LikenessOfTheSeeker.class; + this.getRightHalfCard().setPT(3, 3); // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — You may play an additional land this turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn)); // II — You gain 3 life. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainLifeEffect(3)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new GainLifeEffect(3)); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Likeness of the Seeker + // Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. + this.getRightHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false)); } private AzusasManyJourneys(final AzusasManyJourneys card) { diff --git a/Mage.Sets/src/mage/cards/b/BaSingSe.java b/Mage.Sets/src/mage/cards/b/BaSingSe.java new file mode 100644 index 00000000000..19becb63efa --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BaSingSe.java @@ -0,0 +1,50 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.condition.common.YouControlABasicLandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BaSingSe extends CardImpl { + + public BaSingSe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a basic land. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance) + .addHint(YouControlABasicLandCondition.getHint())); + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // {2}{G}, {T}: Earthbend 2. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new EarthbendTargetEffect(2), new ManaCostsImpl<>("{2}{G}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private BaSingSe(final BaSingSe card) { + super(card); + } + + @Override + public BaSingSe copy() { + return new BaSingSe(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BaboonSpirit.java b/Mage.Sets/src/mage/cards/b/BaboonSpirit.java new file mode 100644 index 00000000000..655bc2179cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BaboonSpirit.java @@ -0,0 +1,64 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect; +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.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.SpiritWorldToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BaboonSpirit extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.SPIRIT, "another nontoken Spirit you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TokenPredicate.FALSE); + } + + public BaboonSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.MONKEY); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever another nontoken Spirit you control enters, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new CreateTokenEffect(new SpiritWorldToken()), filter)); + + // {3}{U}: Exile another target creature you control. Return it to the battlefield under its owner's control at the beginning of the next end step. + Ability ability = new SimpleActivatedAbility( + new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false), new ManaCostsImpl<>("{3}{U}") + ); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private BaboonSpirit(final BaboonSpirit card) { + super(card); + } + + @Override + public BaboonSpirit copy() { + return new BaboonSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Badgermole.java b/Mage.Sets/src/mage/cards/b/Badgermole.java index 24d46635ab7..e849ecf4ea9 100644 --- a/Mage.Sets/src/mage/cards/b/Badgermole.java +++ b/Mage.Sets/src/mage/cards/b/Badgermole.java @@ -39,7 +39,7 @@ public final class Badgermole extends CardImpl { this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( TrampleAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES_P1P1 - ))); + ).setText("creatures you control with +1/+1 counters on them have trample"))); } private Badgermole(final Badgermole card) { diff --git a/Mage.Sets/src/mage/cards/b/BadgermoleCub.java b/Mage.Sets/src/mage/cards/b/BadgermoleCub.java new file mode 100644 index 00000000000..92c28dfcb12 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BadgermoleCub.java @@ -0,0 +1,53 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TapForManaAllTriggeredManaAbility; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BadgermoleCub extends CardImpl { + + public BadgermoleCub(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.BADGER); + this.subtype.add(SubType.MOLE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, earthbend 1. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(1)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // Whenever you tap a creature for mana, add an additional {G}. + this.addAbility(new TapForManaAllTriggeredManaAbility( + new BasicManaEffect(Mana.GreenMana(1)).setText("add an additional {G}"), + StaticFilters.FILTER_CONTROLLED_CREATURE, SetTargetPointer.NONE + ).setTriggerPhrase("Whenever you tap a creature for mana, ")); + } + + private BadgermoleCub(final BadgermoleCub card) { + super(card); + } + + @Override + public BadgermoleCub copy() { + return new BadgermoleCub(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java b/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java deleted file mode 100644 index ccd8cd3eb2a..00000000000 --- a/Mage.Sets/src/mage/cards/b/BahamutWardenOfLight.java +++ /dev/null @@ -1,71 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BahamutWardenOfLight extends CardImpl { - - public BahamutWardenOfLight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setWhite(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Wings of Light -- Put a +1/+1 counter on each other creature you control. Those creatures gain flying until end of turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { - ability.addEffect(new AddCountersAllEffect( - CounterType.P1P1.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE - )); - ability.addEffect(new GainAbilityControlledEffect( - FlyingAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("Those creatures gain flying until end of turn")); - ability.withFlavorWord("Wings of Light"); - }); - - // III -- Gigaflare -- Destroy target permanent. Exile Bahamut, then return it to the battlefield. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new DestroyTargetEffect()); - ability.addEffect(new ExileSourceAndReturnFaceUpEffect()); - ability.addTarget(new TargetPermanent()); - ability.withFlavorWord("Gigaflare"); - }); - this.addAbility(sagaAbility); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private BahamutWardenOfLight(final BahamutWardenOfLight card) { - super(card); - } - - @Override - public BahamutWardenOfLight copy() { - return new BahamutWardenOfLight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BaithookAngler.java b/Mage.Sets/src/mage/cards/b/BaithookAngler.java index 1c3126ea98f..792fa6b9075 100644 --- a/Mage.Sets/src/mage/cards/b/BaithookAngler.java +++ b/Mage.Sets/src/mage/cards/b/BaithookAngler.java @@ -1,10 +1,9 @@ package mage.cards.b; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,19 +12,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BaithookAngler extends CardImpl { +public final class BaithookAngler extends TransformingDoubleFacedCard { public BaithookAngler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.h.HookHauntDrifter.class; + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{U}", + "Hook-Haunt Drifter", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U" + ); + this.getLeftHalfCard().setPT(2, 1); + this.getRightHalfCard().setPT(1, 2); // Disturb {1}{U} - this.addAbility(new DisturbAbility(this, "{1}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{U}")); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BaithookAngler(final BaithookAngler card) { diff --git a/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java b/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java deleted file mode 100644 index 7b34006109d..00000000000 --- a/Mage.Sets/src/mage/cards/b/BalambGardenAirborne.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -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.constants.SuperType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BalambGardenAirborne extends CardImpl { - - public BalambGardenAirborne(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Balamb Garden attacks, draw a card. - this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1))); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private BalambGardenAirborne(final BalambGardenAirborne card) { - super(card); - } - - @Override - public BalambGardenAirborne copy() { - return new BalambGardenAirborne(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java b/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java index 723330f7b88..7c45b3ce32c 100644 --- a/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java +++ b/Mage.Sets/src/mage/cards/b/BalambGardenSeeDAcademy.java @@ -1,6 +1,7 @@ package mage.cards.b; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.CostAdjuster; @@ -8,17 +9,20 @@ 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.DrawCardSourceControllerEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -30,29 +34,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BalambGardenSeeDAcademy extends CardImpl { +public final class BalambGardenSeeDAcademy extends TransformingDoubleFacedCard { public BalambGardenSeeDAcademy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.subtype.add(SubType.TOWN); - this.secondSideCardClazz = mage.cards.b.BalambGardenAirborne.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{SubType.TOWN}, "", + "Balamb Garden, Airborne", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, ""); + this.getRightHalfCard().setPT(5, 4); // This land enters tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTappedAbility()); // Add {G} or {U}. - this.addAbility(new GreenManaAbility()); - this.addAbility(new BlueManaAbility()); + this.getLeftHalfCard().addAbility(new GreenManaAbility()); + this.getLeftHalfCard().addAbility(new BlueManaAbility()); // {5}{G}{U}, {T}: Transform this land. This ability costs {1} less to activate for each other Town you control. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}{U}")); ability.addCost(new TapSourceCost()); ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each other Town you control")); - this.addAbility(ability + this.getLeftHalfCard().addAbility(ability .setCostAdjuster(BalambGardenSeeDAcademyAdjuster.instance) .addHint(BalambGardenSeeDAcademyAdjuster.getHint())); + + // Balamb Garden, Airborne + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Balamb Garden attacks, draw a card. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private BalambGardenSeeDAcademy(final BalambGardenSeeDAcademy card) { diff --git a/Mage.Sets/src/mage/cards/b/BallistaWatcher.java b/Mage.Sets/src/mage/cards/b/BallistaWatcher.java index 809f160eda2..3ae2e3066ec 100644 --- a/Mage.Sets/src/mage/cards/b/BallistaWatcher.java +++ b/Mage.Sets/src/mage/cards/b/BallistaWatcher.java @@ -1,16 +1,23 @@ package mage.cards.b; -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.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.players.Player; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -18,17 +25,16 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BallistaWatcher extends CardImpl { +public final class BallistaWatcher extends TransformingDoubleFacedCard { public BallistaWatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER, SubType.WEREWOLF}, "{2}{R}{R}", + "Ballista Wielder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BallistaWielder.class; + // Ballista Watcher + this.getLeftHalfCard().setPT(4, 3); // {2}{R}, {T}: Ballista Watcher deals 1 damage to any target. Ability ability = new SimpleActivatedAbility( @@ -36,10 +42,21 @@ public final class BallistaWatcher extends CardImpl { ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Ballista Wielder + this.getRightHalfCard().setPT(5, 5); + + // {2}{R}: Ballista Wielder deals 1 damage to any target. A creature dealt damage this way can't block this turn. + Ability weilderAbility = new SimpleActivatedAbility(new BallistaWielderEffect(), new ManaCostsImpl<>("{2}{R}")); + weilderAbility.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(weilderAbility); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BallistaWatcher(final BallistaWatcher card) { @@ -51,3 +68,34 @@ public final class BallistaWatcher extends CardImpl { return new BallistaWatcher(this); } } + +class BallistaWielderEffect extends OneShotEffect { + + BallistaWielderEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to any target. A creature dealt damage this way can't block this turn"; + } + + private BallistaWielderEffect(final BallistaWielderEffect effect) { + super(effect); + } + + @Override + public BallistaWielderEffect copy() { + return new BallistaWielderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + return player != null && player.damage(1, source, game) > 0; + } + if (permanent.damage(1, source, game) <= 0) { + return false; + } + game.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BallistaWielder.java b/Mage.Sets/src/mage/cards/b/BallistaWielder.java deleted file mode 100644 index 81c2dd0ad50..00000000000 --- a/Mage.Sets/src/mage/cards/b/BallistaWielder.java +++ /dev/null @@ -1,85 +0,0 @@ -package mage.cards.b; - -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.combat.CantBlockTargetEffect; -import mage.abilities.keyword.NightboundAbility; -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.players.Player; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BallistaWielder extends CardImpl { - - public BallistaWielder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.nightCard = true; - - // {2}{R}: Ballista Wielder deals 1 damage to any target. A creature dealt damage this way can't block this turn. - Ability ability = new SimpleActivatedAbility(new BallistaWielderEffect(), new ManaCostsImpl<>("{2}{R}")); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private BallistaWielder(final BallistaWielder card) { - super(card); - } - - @Override - public BallistaWielder copy() { - return new BallistaWielder(this); - } -} - -class BallistaWielderEffect extends OneShotEffect { - - BallistaWielderEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 1 damage to any target. A creature dealt damage this way can't block this turn"; - } - - private BallistaWielderEffect(final BallistaWielderEffect effect) { - super(effect); - } - - @Override - public BallistaWielderEffect copy() { - return new BallistaWielderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - return player != null && player.damage(1, source, game) > 0; - } - if (permanent.damage(1, source, game) <= 0) { - return false; - } - game.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BaneOfHanweir.java b/Mage.Sets/src/mage/cards/b/BaneOfHanweir.java deleted file mode 100644 index db8f96ac32a..00000000000 --- a/Mage.Sets/src/mage/cards/b/BaneOfHanweir.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.AttacksEachCombatStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class BaneOfHanweir extends CardImpl { - - public BaneOfHanweir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // Bane of Hanweir attacks each turn if able. - this.addAbility(new AttacksEachCombatStaticAbility()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Bane of Hanweir. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private BaneOfHanweir(final BaneOfHanweir card) { - super(card); - } - - @Override - public BaneOfHanweir copy() { - return new BaneOfHanweir(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java b/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java index 7645832128f..8615e59e7cf 100644 --- a/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java +++ b/Mage.Sets/src/mage/cards/b/BanebladeScoundrel.java @@ -1,11 +1,13 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetControllerEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -17,31 +19,47 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BanebladeScoundrel extends CardImpl { +public final class BanebladeScoundrel extends TransformingDoubleFacedCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); static { filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); } public BanebladeScoundrel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{3}{B}", + "Baneclaw Marauder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BaneclawMarauder.class; + // Baneblade Scoundrel + this.getLeftHalfCard().setPT(4, 3); // Whenever Baneblade Scoundrel becomes blocked, each creature blocking it gets -1/-1 until end of turn. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( + this.getLeftHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( -1, -1, Duration.EndOfTurn, filter, false ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Baneclaw Marauder + this.getRightHalfCard().setPT(5, 4); + + // Whenever Baneclaw Marauder becomes blocked, each creature blocking it gets -1/-1 until end of turn. + this.getRightHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, filter, false + ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); + + // Whenever a creature blocking Baneclaw Marauder dies, its controller loses 1 life. + this.getRightHalfCard().addAbility(new DiesCreatureTriggeredAbility( + new LoseLifeTargetControllerEffect(1) + .setText("that creature's controller loses 1 life"), + false, filter, true + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BanebladeScoundrel(final BanebladeScoundrel card) { diff --git a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java b/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java deleted file mode 100644 index 668dd16535e..00000000000 --- a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; -import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.effects.common.LoseLifeTargetControllerEffect; -import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.keyword.NightboundAbility; -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.permanent.BlockingOrBlockedBySourcePredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BaneclawMarauder extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature blocking {this}"); - - static { - filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); - } - - public BaneclawMarauder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever Baneclaw Marauder becomes blocked, each creature blocking it gets -1/-1 until end of turn. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new BoostAllEffect( - -1, -1, Duration.EndOfTurn, filter, false - ).setText("each creature blocking it gets -1/-1 until end of turn"), false)); - - // Whenever a creature blocking Baneclaw Marauder dies, its controller loses 1 life. - this.addAbility(new DiesCreatureTriggeredAbility( - new LoseLifeTargetControllerEffect(1) - .setText("that creature's controller loses 1 life"), - false, filter, true - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private BaneclawMarauder(final BaneclawMarauder card) { - super(card); - } - - @Override - public BaneclawMarauder copy() { - return new BaneclawMarauder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BaradDur.java b/Mage.Sets/src/mage/cards/b/BaradDur.java index d51f2572517..0a448e697a4 100644 --- a/Mage.Sets/src/mage/cards/b/BaradDur.java +++ b/Mage.Sets/src/mage/cards/b/BaradDur.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; import mage.abilities.condition.common.MorbidCondition; -import mage.abilities.condition.common.YouControlPermanentCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.GetXValue; @@ -16,8 +16,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import java.util.UUID; @@ -26,21 +24,14 @@ import java.util.UUID; */ public final class BaradDur extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter); - public BaradDur(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); // Barad-dur enters the battlefield tapped unless you control a legendary creature. - this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint())); + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); // {T}: Add {B}. this.addAbility(new BlackManaAbility()); diff --git a/Mage.Sets/src/mage/cards/b/BarracksOfTheThousand.java b/Mage.Sets/src/mage/cards/b/BarracksOfTheThousand.java deleted file mode 100644 index 5a462272b46..00000000000 --- a/Mage.Sets/src/mage/cards/b/BarracksOfTheThousand.java +++ /dev/null @@ -1,56 +0,0 @@ -package mage.cards.b; - -import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.mana.WhiteManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.filter.FilterSpell; -import mage.filter.predicate.Predicates; -import mage.game.permanent.token.GnomeSoldierStarStarToken; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class BarracksOfTheThousand extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("an artifact or creature spell"); - - static { - filter.add(Predicates.or( - CardType.ARTIFACT.getPredicate(), - CardType.CREATURE.getPredicate() - )); - } - - public BarracksOfTheThousand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - // (Transforms from Thousand Moons Smithy.) - this.nightCard = true; - - // {T}: Add {W}. - this.addAbility(new WhiteManaAbility()); - - // Whenever you cast an artifact or creature spell using mana produced by Barracks of the Thousand, create a white Gnome Soldier artifact creature token with "This creature's power and toughness are each equal to the number of artifacts and/or creatures you control." - this.addAbility(new CastSpellPaidBySourceTriggeredAbility( - new CreateTokenEffect(new GnomeSoldierStarStarToken()), - filter, false - )); - } - - private BarracksOfTheThousand(final BarracksOfTheThousand card) { - super(card); - } - - @Override - public BarracksOfTheThousand copy() { - return new BarracksOfTheThousand(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BarretWallace.java b/Mage.Sets/src/mage/cards/b/BarretWallace.java index e040ec94df4..df2a98d233d 100644 --- a/Mage.Sets/src/mage/cards/b/BarretWallace.java +++ b/Mage.Sets/src/mage/cards/b/BarretWallace.java @@ -49,10 +49,10 @@ public final class BarretWallace extends CardImpl { // Whenever Barret Wallace attacks, it deals damage equal to the number of equipped creatures you control to defending player. this.addAbility(new AttacksTriggeredAbility( - new DamageTargetEffect(xValue, true, "it", true) + new DamageTargetEffect(xValue) .setText("it deals damage equal to the number of equipped creatures you control to defending player"), false, null, SetTargetPointer.PLAYER - ).withRuleTextReplacement(true).addHint(hint)); + ).addHint(hint)); } private BarretWallace(final BarretWallace card) { diff --git a/Mage.Sets/src/mage/cards/b/BasaltGolem.java b/Mage.Sets/src/mage/cards/b/BasaltGolem.java index f13c6b69fe7..908e1eaeeb5 100644 --- a/Mage.Sets/src/mage/cards/b/BasaltGolem.java +++ b/Mage.Sets/src/mage/cards/b/BasaltGolem.java @@ -19,7 +19,7 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.WallToken; +import mage.game.permanent.token.BasaltGolemToken; import mage.players.Player; /** @@ -30,7 +30,7 @@ public final class BasaltGolem extends CardImpl { public BasaltGolem(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); - + this.subtype.add(SubType.GOLEM); this.power = new MageInt(2); this.toughness = new MageInt(4); @@ -83,6 +83,6 @@ class BasaltGolemEffect extends OneShotEffect { if (!creature.sacrifice(source, game)) return false; - return new WallToken().putOntoBattlefield(1, game, source, player.getId()); + return new BasaltGolemToken().putOntoBattlefield(1, game, source, player.getId()); } } diff --git a/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java b/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java index 779418b1cd0..e7c0020b3fe 100644 --- a/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java +++ b/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java @@ -7,13 +7,13 @@ import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.PreventionEffectImpl; 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.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.players.Player; import java.util.UUID; @@ -46,7 +46,7 @@ public final class BattletideAlchemist extends CardImpl { class BattletideAlchemistEffect extends PreventionEffectImpl { BattletideAlchemistEffect() { - super(Duration.WhileOnBattlefield); + super(Duration.WhileOnBattlefield, 0, false, false, new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.CLERIC, "Clerics"))); this.staticText = "If a source would deal damage to a player, you may prevent X of that damage, where X is the number of Clerics you control"; } @@ -61,27 +61,14 @@ class BattletideAlchemistEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - boolean result = false; Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(event.getTargetId()); if (controller != null && targetPlayer != null) { - int numberOfClericsControlled = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.CLERIC, "Clerics")).calculate(game, source, this); - int toPrevent = Math.min(numberOfClericsControlled, event.getAmount()); - if (toPrevent > 0 && controller.chooseUse(Outcome.PreventDamage, "Prevent " + toPrevent + " damage to " + targetPlayer.getName() + '?', source, game)) { - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent, ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - if (event.getAmount() >= toPrevent) { - event.setAmount(event.getAmount() - toPrevent); - } else { - event.setAmount(0); - result = true; - } - game.informPlayers("Battletide Alchemist prevented " + toPrevent + " damage to " + targetPlayer.getName()); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent)); + if (amountToPrevent > 0 && controller.chooseUse(Outcome.PreventDamage, "Prevent " + amountToPrevent + " damage to " + targetPlayer.getName() + '?', source, game)) { + preventDamageAction(event, source, game); } } - } - return result; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java b/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java deleted file mode 100644 index 655b7b2834a..00000000000 --- a/Mage.Sets/src/mage/cards/b/BearerOfOverwhelmingTruths.java +++ /dev/null @@ -1,45 +0,0 @@ - -package mage.cards.b; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.keyword.InvestigateEffect; -import mage.abilities.keyword.ProwessAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class BearerOfOverwhelmingTruths extends CardImpl { - - public BearerOfOverwhelmingTruths(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN, SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Prowess - this.addAbility(new ProwessAbility()); - - // Whenever Bearer of Overwhelming Truths deals combat damage to a player, investigate. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new InvestigateEffect(), false)); - } - - private BearerOfOverwhelmingTruths(final BearerOfOverwhelmingTruths card) { - super(card); - } - - @Override - public BearerOfOverwhelmingTruths copy() { - return new BearerOfOverwhelmingTruths(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BebopAndRocksteady.java b/Mage.Sets/src/mage/cards/b/BebopAndRocksteady.java new file mode 100644 index 00000000000..2a9f7cfe058 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BebopAndRocksteady.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.SacrificeControllerEffect; +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 BebopAndRocksteady extends CardImpl { + + public BebopAndRocksteady(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/G}{B/G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BOAR); + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(7); + this.toughness = new MageInt(5); + + // Whenever Bebop & Rocksteady attacks or blocks, sacrifice a permanent unless you discard a card. + this.addAbility(new AttacksOrBlocksTriggeredAbility(new DoIfCostPaid( + null, new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT, 1, null), + new DiscardCardCost(), true), false + )); + } + + private BebopAndRocksteady(final BebopAndRocksteady card) { + super(card); + } + + @Override + public BebopAndRocksteady copy() { + return new BebopAndRocksteady(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java b/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java index b0b65e3af98..2b76d6a4d8c 100644 --- a/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java +++ b/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java @@ -1,7 +1,6 @@ package mage.cards.b; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -75,9 +74,9 @@ class BedazzleEffect extends OneShotEffect { if (permanent != null) { permanent.destroy(source, game, false); } - Effect effect = new DamageTargetEffect(StaticValue.get(2), true, "", true); + Effect effect = new DamageTargetEffect(2); effect.setTargetPointer(new FixedTarget(source.getTargets().get(1).getFirstTarget(), game)); effect.apply(game, source); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java b/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java index 23ce37cae8a..5bfa5cc39ce 100644 --- a/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java +++ b/Mage.Sets/src/mage/cards/b/BefriendingTheMoths.java @@ -6,9 +6,8 @@ import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; @@ -19,20 +18,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BefriendingTheMoths extends CardImpl { +public final class BefriendingTheMoths extends TransformingDoubleFacedCard { public BefriendingTheMoths(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.i.ImperialMoth.class; + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{W}", + "Imperial Moth", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.INSECT}, "W"); + // Befriending the Moths // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I, II — Target creature you control gets +1/+1 and gains flying until end of turn. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new Effects( new BoostTargetEffect(1, 1) .setText("target creature you control gets +1/+1"), @@ -42,10 +41,14 @@ public final class BefriendingTheMoths extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Imperial Moth + this.getRightHalfCard().setPT(2, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private BefriendingTheMoths(final BefriendingTheMoths card) { diff --git a/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java index c42d0c20e54..bbf412e6f26 100644 --- a/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java +++ b/Mage.Sets/src/mage/cards/b/BeholdTheUnspeakable.java @@ -1,15 +1,19 @@ package mage.cards.b; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.HeckbentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; @@ -21,35 +25,49 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BeholdTheUnspeakable extends CardImpl { +public final class BeholdTheUnspeakable extends TransformingDoubleFacedCard { public BeholdTheUnspeakable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.v.VisionOfTheUnspeakable.class; + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{U}{U}", + "Vision of the Unspeakable", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); + // Behold the Unspeakable // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I — Creatures you don't control get -2/-0 until your next turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new BoostAllEffect( + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_I, new BoostAllEffect( -2, 0, Duration.UntilYourNextTurn, StaticFilters.FILTER_CREATURES_YOU_DONT_CONTROL, false )); // II — If you have one or fewer cards in hand, draw four cards. Otherwise, scry 2, then draw two cards. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new ConditionalOneShotEffect( + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_II, new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(4), new ScryEffect(2), HeckbentCondition.instance, "if you have one or fewer cards in hand, " + "draw four cards. Otherwise, scry 2, then draw two cards" ).addOtherwiseEffect(new DrawCardSourceControllerEffect(2))); // 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()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Vision of the Unspeakable + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Vision of the Unspeakable gets +1/+1 for each card in your hand. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostSourceEffect( + CardsInControllerHandCount.ANY_SINGULAR, + CardsInControllerHandCount.ANY_SINGULAR, + Duration.WhileOnBattlefield + ))); } private BeholdTheUnspeakable(final BeholdTheUnspeakable card) { diff --git a/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java b/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java new file mode 100644 index 00000000000..6c47f575379 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BeifongsBountyHunters.java @@ -0,0 +1,87 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BeifongsBountyHunters extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nonland creature you control"); + + static { + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + public BeifongsBountyHunters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever a nonland creature you control dies, earthbend X, where X is that creature's power. + Ability ability = new DiesCreatureTriggeredAbility( + new EarthbendTargetEffect(BeifongsBountyHuntersValue.instance, true), false, filter + ); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private BeifongsBountyHunters(final BeifongsBountyHunters card) { + super(card); + } + + @Override + public BeifongsBountyHunters copy() { + return new BeifongsBountyHunters(this); + } +} + +enum BeifongsBountyHuntersValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional + .ofNullable((Permanent) effect.getValue("creatureDied")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + } + + @Override + public BeifongsBountyHuntersValue 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/b/BelenonWarAnthem.java b/Mage.Sets/src/mage/cards/b/BelenonWarAnthem.java deleted file mode 100644 index 432533a985b..00000000000 --- a/Mage.Sets/src/mage/cards/b/BelenonWarAnthem.java +++ /dev/null @@ -1,35 +0,0 @@ -package mage.cards.b; - -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.Duration; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BelenonWarAnthem extends CardImpl { - - public BelenonWarAnthem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.nightCard = true; - - // Creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); - } - - private BelenonWarAnthem(final BelenonWarAnthem card) { - super(card); - } - - @Override - public BelenonWarAnthem copy() { - return new BelenonWarAnthem(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BelligerentRegisaur.java b/Mage.Sets/src/mage/cards/b/BelligerentRegisaur.java deleted file mode 100644 index 030117c9ab4..00000000000 --- a/Mage.Sets/src/mage/cards/b/BelligerentRegisaur.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.IndestructibleAbility; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BelligerentRegisaur extends CardImpl { - - public BelligerentRegisaur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever you cast a spell, Belligerent Regisaur gains indestructible until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn - ), false)); - } - - private BelligerentRegisaur(final BelligerentRegisaur card) { - super(card); - } - - @Override - public BelligerentRegisaur copy() { - return new BelligerentRegisaur(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BellowingFiend.java b/Mage.Sets/src/mage/cards/b/BellowingFiend.java index 7638ae26eb9..b38acec47c7 100644 --- a/Mage.Sets/src/mage/cards/b/BellowingFiend.java +++ b/Mage.Sets/src/mage/cards/b/BellowingFiend.java @@ -3,9 +3,7 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToACreatureTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -31,12 +29,10 @@ public final class BellowingFiend extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Whenever Bellowing Fiend deals damage to a creature, Bellowing Fiend deals 3 damage to that creature's controller and 3 damage to you. - Ability ability = new DealsDamageToACreatureTriggeredAbility(new BellowingFiendEffect(), false, false, true); - Effect effect = new DamageControllerEffect(3); - effect.setText("and 3 damage to you"); - ability.addEffect(effect); - this.addAbility(ability); + this.addAbility(new DealsDamageToACreatureTriggeredAbility( + new BellowingFiendEffect(), false, false, true)); } private BellowingFiend(final BellowingFiend card) { @@ -53,7 +49,7 @@ class BellowingFiendEffect extends OneShotEffect { BellowingFiendEffect() { super(Outcome.Detriment); - this.staticText = "{this} deals 3 damage to that creature's controller"; + this.staticText = "{this} deals 3 damage to that creature's controller and 3 damage to you"; } private BellowingFiendEffect(final BellowingFiendEffect effect) { @@ -67,15 +63,17 @@ class BellowingFiendEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean applied = false; Permanent damagedCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); if (damagedCreature != null) { Player controller = game.getPlayer(damagedCreature.getControllerId()); if (controller != null) { controller.damage(3, source.getSourceId(), source, game); - applied = true; } } - return applied; + Player you = game.getPlayer(source.getControllerId()); + if (you != null) { + you.damage(3, source.getSourceId(), source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java index a07558efdd3..6ee16a8e389 100644 --- a/Mage.Sets/src/mage/cards/b/BelovedBeggar.java +++ b/Mage.Sets/src/mage/cards/b/BelovedBeggar.java @@ -1,10 +1,10 @@ package mage.cards.b; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,20 +13,27 @@ import java.util.UUID; /** * @author weirddan455 */ -public final class BelovedBeggar extends CardImpl { +public final class BelovedBeggar extends TransformingDoubleFacedCard { public BelovedBeggar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.g.GenerousSoul.class; + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{W}", + "Generous Soul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "W"); + this.getLeftHalfCard().setPT(0, 4); + this.getRightHalfCard().setPT(4, 4); // Disturb {4}{W}{W} - this.addAbility(new DisturbAbility(this, "{4}{W}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{W}{W}")); + + // Generous Soul + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // If Generous Soul would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BelovedBeggar(final BelovedBeggar card) { diff --git a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java index 7fd9c9d7903..f9f263deb35 100644 --- a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java +++ b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java @@ -39,7 +39,7 @@ public final class BenBenAkkiHermit extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter), true), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)), new TapSourceCost()); ability.addTarget(new TargetAttackingCreature()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BenevolentGeist.java b/Mage.Sets/src/mage/cards/b/BenevolentGeist.java deleted file mode 100644 index 69c570a5580..00000000000 --- a/Mage.Sets/src/mage/cards/b/BenevolentGeist.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantBeCounteredControlledEffect; -import mage.abilities.keyword.DisturbAbility; -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.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BenevolentGeist extends CardImpl { - - public BenevolentGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Noncreature spells you control can't be countered. - this.addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect( - StaticFilters.FILTER_SPELLS_NON_CREATURE, Duration.WhileOnBattlefield - ))); - - // If Benevolent Geist would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private BenevolentGeist(final BenevolentGeist card) { - super(card); - } - - @Override - public BenevolentGeist copy() { - return new BenevolentGeist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java b/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java new file mode 100644 index 00000000000..25038e78824 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BenevolentRiverSpirit.java @@ -0,0 +1,50 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.keyword.ScryEffect; +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.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BenevolentRiverSpirit extends CardImpl { + + public BenevolentRiverSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // As an additional cost to cast this spell, waterbend {5}. + this.getSpellAbility().addCost(new WaterbendCost(5)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + + // When this creature enters, scry 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + } + + private BenevolentRiverSpirit(final BenevolentRiverSpirit card) { + super(card); + } + + @Override + public BenevolentRiverSpirit copy() { + return new BenevolentRiverSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java b/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java index 463b0716483..28e3e704c72 100644 --- a/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java +++ b/Mage.Sets/src/mage/cards/b/BereavedSurvivor.java @@ -1,37 +1,56 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class BereavedSurvivor extends CardImpl { +public final class BereavedSurvivor extends TransformingDoubleFacedCard { + 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 BereavedSurvivor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{2}{W}", + "Dauntless Avenger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "W"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DauntlessAvenger.class; + // Bereaved Survivor + this.getLeftHalfCard().setPT(2, 1); // When another creature you control dies, transform Bereaved Survivor. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( new TransformSourceEffect(), false, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE ).setTriggerPhrase("When another creature you control dies, ")); + + // Dauntless Avenger + this.getRightHalfCard().setPT(3, 2); + + // Whenever Dauntless Avenger attacks, return target creature card with mana value 2 or less from your graveyard to the battlefield tapped and attacking. + Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true, true)); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.getRightHalfCard().addAbility(ability); } private BereavedSurvivor(final BereavedSurvivor card) { diff --git a/Mage.Sets/src/mage/cards/b/BindingGeist.java b/Mage.Sets/src/mage/cards/b/BindingGeist.java index df255c28543..68c7ed88e96 100644 --- a/Mage.Sets/src/mage/cards/b/BindingGeist.java +++ b/Mage.Sets/src/mage/cards/b/BindingGeist.java @@ -1,15 +1,20 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -17,23 +22,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BindingGeist extends CardImpl { +public final class BindingGeist extends TransformingDoubleFacedCard { public BindingGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{U}", + "Spectral Binding", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SpectralBinding.class; + // Binding Geist + this.getLeftHalfCard().setPT(3, 1); // Whenever Binding Geist attacks, target creature an opponent controls gets -2/-0 until end of turn. Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect(-2, 0)); ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Spectral Binding + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {1}{U} - this.addAbility(new DisturbAbility(this, "{1}{U}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{U}")); + + // Enchanted creature gets -2/-0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-2, 0))); + + // If Spectral Binding would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BindingGeist(final BindingGeist card) { diff --git a/Mage.Sets/src/mage/cards/b/BiolumeEgg.java b/Mage.Sets/src/mage/cards/b/BiolumeEgg.java index 9f5b8140020..83ed25e5abc 100644 --- a/Mage.Sets/src/mage/cards/b/BiolumeEgg.java +++ b/Mage.Sets/src/mage/cards/b/BiolumeEgg.java @@ -1,22 +1,22 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SacrificeSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.TransformAbility; 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.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; @@ -25,28 +25,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BiolumeEgg extends CardImpl { +public final class BiolumeEgg extends TransformingDoubleFacedCard { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.ISLAND, "Islands"); public BiolumeEgg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SERPENT, SubType.EGG}, "{2}{U}", + "Biolume Serpent", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SERPENT}, "U"); - this.subtype.add(SubType.SERPENT); - this.subtype.add(SubType.EGG); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.b.BiolumeSerpent.class; + // Biolume Egg + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // When Biolume Egg enters the battlefield, scry 2. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); // When you sacrifice Biolume Egg, return it to the battlefield transformed under its owner's control at the beginning of the next end step. - this.addAbility(new TransformAbility()); - this.addAbility(new SacrificeSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new SacrificeSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new BiolumeEggEffect()), true ).setText("return it to the battlefield transformed under its owner's control at the beginning of the next end step"), false, true)); + + // Biolume Serpent + this.getRightHalfCard().setPT(4, 4); + + // Sacrifice two Islands: Biolume Serpent can't be blocked this turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), + new SacrificeTargetCost(2, filter) + )); } private BiolumeEgg(final BiolumeEgg card) { diff --git a/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java b/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java deleted file mode 100644 index bcee214b7b3..00000000000 --- a/Mage.Sets/src/mage/cards/b/BiolumeSerpent.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -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.target.common.TargetControlledPermanent; -import mage.target.common.TargetSacrifice; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BiolumeSerpent extends CardImpl { - - private static final FilterControlledPermanent filter - = new FilterControlledPermanent(SubType.ISLAND, "Islands"); - - public BiolumeSerpent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SERPENT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.nightCard = true; - - // Sacrifice two Islands: Biolume Serpent can't be blocked this turn. - this.addAbility(new SimpleActivatedAbility( - new CantBeBlockedSourceEffect(Duration.EndOfTurn), - new SacrificeTargetCost(2, filter) - )); - } - - private BiolumeSerpent(final BiolumeSerpent card) { - super(card); - } - - @Override - public BiolumeSerpent copy() { - return new BiolumeSerpent(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BirdAdmirer.java b/Mage.Sets/src/mage/cards/b/BirdAdmirer.java index b724b703f26..5eb9664ae7d 100644 --- a/Mage.Sets/src/mage/cards/b/BirdAdmirer.java +++ b/Mage.Sets/src/mage/cards/b/BirdAdmirer.java @@ -1,10 +1,10 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,23 +13,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BirdAdmirer extends CardImpl { +public final class BirdAdmirer extends TransformingDoubleFacedCard { public BirdAdmirer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ARCHER, SubType.WEREWOLF}, "{2}{G}", + "Wing Shredder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ARCHER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.w.WingShredder.class; + // Bird Admirer + this.getLeftHalfCard().setPT(1, 4); // Reach - this.addAbility(ReachAbility.getInstance()); + this.getLeftHalfCard().addAbility(ReachAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Wing Shredder + this.getRightHalfCard().setPT(3, 5); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BirdAdmirer(final BirdAdmirer card) { diff --git a/Mage.Sets/src/mage/cards/b/BisonWhistle.java b/Mage.Sets/src/mage/cards/b/BisonWhistle.java new file mode 100644 index 00000000000..19cfa97f413 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BisonWhistle.java @@ -0,0 +1,93 @@ +package mage.cards.b; + +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.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.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BisonWhistle extends CardImpl { + + public BisonWhistle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}"); + + // {1}, {T}: Look at the top card of your library. If it's a Bison card, you may put it onto the battlefield. If it's a creature card, you may reveal it and put it into your hand. Otherwise, you may put it into your graveyard. + Ability ability = new SimpleActivatedAbility(new BisonWhistleEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private BisonWhistle(final BisonWhistle card) { + super(card); + } + + @Override + public BisonWhistle copy() { + return new BisonWhistle(this); + } +} + +class BisonWhistleEffect extends OneShotEffect { + + BisonWhistleEffect() { + super(Outcome.Benefit); + staticText = "look at the top card of your library. If it's a Bison card, you may put it onto the battlefield. " + + "If it's a creature card, you may reveal it and put it into your hand. Otherwise, you may put it into your graveyard"; + } + + private BisonWhistleEffect(final BisonWhistleEffect effect) { + super(effect); + } + + @Override + public BisonWhistleEffect copy() { + return new BisonWhistleEffect(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 library", card, game); + if (card.hasSubtype(SubType.BISON, game) && player.chooseUse( + Outcome.PutCardInPlay, "Put " + card.getIdName() + " onto the battlefield?", source, game + )) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + // cards like Crib Swap and Containment Priest make it possible for the card + // to either stay in the library or go to a different zone, so we only exit if it's not still on top + if (!Zone.LIBRARY.match(game.getState().getZone(card.getId()))) { + return true; + } + } + if (card.isCreature(game) && player.chooseUse( + Outcome.DrawCard, "Put " + card.getIdName() + " into your hand?", source, game + )) { + player.revealCards(source, new CardsImpl(card), game); + return player.moveCards(card, Zone.HAND, source, game); + } + return player.chooseUse( + Outcome.Discard, "Put " + card.getIdName() + " into your graveyard?", source, game + ) && player.moveCards(card, Zone.GRAVEYARD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BitterWork.java b/Mage.Sets/src/mage/cards/b/BitterWork.java new file mode 100644 index 00000000000..8b941f867c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BitterWork.java @@ -0,0 +1,58 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.ExhaustAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SetTargetPointer; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BitterWork extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public BitterWork(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{G}"); + + // Whenever you attack a player with one or more creatures with power 4 or greater, draw a card. + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, SetTargetPointer.NONE + ).setTriggerPhrase("Whenever you attack a player with one or more creatures with power 4 or greater, ")); + + // Exhaust -- {4}: Earthbend 4. Activate only during your turn. + Ability ability = new ExhaustAbility(new EarthbendTargetEffect(4), new GenericManaCost(4)) + .setCondition(MyTurnCondition.instance); + ability.addTarget(new TargetControlledLandPermanent()); + ability.addEffect(new InfoEffect("Activate only during your turn")); + this.addAbility(ability); + } + + private BitterWork(final BitterWork card) { + super(card); + } + + @Override + public BitterWork copy() { + return new BitterWork(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlackChocobo.java b/Mage.Sets/src/mage/cards/b/BlackChocobo.java deleted file mode 100644 index 9b6dc77adfe..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlackChocobo.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.LandfallAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -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.StaticFilters; -import mage.target.common.TargetCardInLibrary; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BlackChocobo extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(SubType.BIRD, "Birds"); - - public BlackChocobo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.BIRD); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.nightCard = true; - this.color.setGreen(true); - - // When this permanent transforms into Black Chocobo, search your library for a land card, put it onto the battlefield tapped, then shuffle. - this.addAbility(new TransformIntoSourceTriggeredAbility( - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_LAND_A), true) - )); - - // Landfall -- Whenever a land you control enters, Birds you control get +1/+0 until end of turn. - this.addAbility(new LandfallAbility(new BoostControlledEffect( - 1, 0, Duration.EndOfTurn, filter, false - ))); - } - - private BlackChocobo(final BlackChocobo card) { - super(card); - } - - @Override - public BlackChocobo copy() { - return new BlackChocobo(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BladewheelChariot.java b/Mage.Sets/src/mage/cards/b/BladewheelChariot.java deleted file mode 100644 index aa6b22cf8aa..00000000000 --- a/Mage.Sets/src/mage/cards/b/BladewheelChariot.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapTargetCost; -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.FilterControlledArtifactPermanent; -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 BladewheelChariot extends CardImpl { - - private static final FilterControlledPermanent filter - = new FilterControlledArtifactPermanent("other untapped artifacts you control"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(TappedPredicate.UNTAPPED); - } - - public BladewheelChariot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setWhite(true); - - // Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn. - this.addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect( - Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE - ).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, filter)))); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private BladewheelChariot(final BladewheelChariot card) { - super(card); - } - - @Override - public BladewheelChariot copy() { - return new BladewheelChariot(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java b/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java index a5cd19e5727..2410b9e2b66 100644 --- a/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java +++ b/Mage.Sets/src/mage/cards/b/BlightreaperThallid.java @@ -1,33 +1,48 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.PhyrexianSaprolingToken; import java.util.UUID; /** * @author TheElk801 */ -public final class BlightreaperThallid extends CardImpl { +public final class BlightreaperThallid extends TransformingDoubleFacedCard { public BlightreaperThallid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS}, "{1}{B}", + "Blightsower Thallid", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.FUNGUS}, "BG"); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.b.BlightsowerThallid.class; + // Blightreaper Thallid + this.getLeftHalfCard().setPT(2, 2); // {3}{G/P}: Transform Blightreaper Thallid. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{G/P}"))); + + // Blightsower Thallid + this.getRightHalfCard().setPT(3, 3); + + // When this creature transforms into Blightsower Thallid or dies, create a 1/1 green Phyrexian Saproling creature token. + this.getRightHalfCard().addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianSaprolingToken()), false, + "When this creature transforms into {this} or dies, ", + new TransformIntoSourceTriggeredAbility(null), + new DiesSourceTriggeredAbility(null, false) + )); } private BlightreaperThallid(final BlightreaperThallid card) { diff --git a/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java b/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java deleted file mode 100644 index 62a5dd8ab40..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlightsowerThallid.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -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.PhyrexianSaprolingToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BlightsowerThallid extends CardImpl { - - public BlightsowerThallid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.color.setGreen(true); - this.nightCard = true; - - // When this creature transforms into Blightsower Thallid or dies, create a 1/1 green Phyrexian Saproling creature token. - this.addAbility(new OrTriggeredAbility( - Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianSaprolingToken()), false, - "When this creature transforms into {this} or dies, ", - new TransformIntoSourceTriggeredAbility(null), - new DiesSourceTriggeredAbility(null, false) - )); - } - - private BlightsowerThallid(final BlightsowerThallid card) { - super(card); - } - - @Override - public BlightsowerThallid copy() { - return new BlightsowerThallid(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java b/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java deleted file mode 100644 index bf76a3de6bd..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlitzwingAdaptiveAssailant.java +++ /dev/null @@ -1,83 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.util.RandomUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BlitzwingAdaptiveAssailant extends CardImpl { - - public BlitzwingAdaptiveAssailant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // At the beginning of combat on your turn, choose flying or indestructible at random. Blitzwing gains that ability until end of turn. - this.addAbility(new BeginningOfCombatTriggeredAbility( - new BlitzwingAdaptiveAssailantEffect() - )); - - // Whenever Blitzwing deals combat damage to a player, convert it. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new TransformSourceEffect().setText("convert it"), false - )); - } - - private BlitzwingAdaptiveAssailant(final BlitzwingAdaptiveAssailant card) { - super(card); - } - - @Override - public BlitzwingAdaptiveAssailant copy() { - return new BlitzwingAdaptiveAssailant(this); - } -} - -class BlitzwingAdaptiveAssailantEffect extends OneShotEffect { - - BlitzwingAdaptiveAssailantEffect() { - super(Outcome.Benefit); - staticText = "choose flying or indestructible at random. {this} gains that ability until end of turn"; - } - - private BlitzwingAdaptiveAssailantEffect(final BlitzwingAdaptiveAssailantEffect effect) { - super(effect); - } - - @Override - public BlitzwingAdaptiveAssailantEffect copy() { - return new BlitzwingAdaptiveAssailantEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Ability ability = RandomUtil.nextBoolean() ? FlyingAbility.getInstance() : IndestructibleAbility.getInstance(); - game.informPlayers(ability.getRule() + " has been chosen"); - game.addEffect(new GainAbilitySourceEffect(ability, Duration.EndOfTurn), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java b/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java index effa3be1f7a..22583cb96c9 100644 --- a/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java +++ b/Mage.Sets/src/mage/cards/b/BlitzwingCruelTormentor.java @@ -1,17 +1,24 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.RandomUtil; import mage.watchers.common.PlayerLostLifeWatcher; import java.util.UUID; @@ -19,26 +26,43 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BlitzwingCruelTormentor extends CardImpl { +public final class BlitzwingCruelTormentor extends TransformingDoubleFacedCard { public BlitzwingCruelTormentor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{5}{B}", + "Blitzwing Adaptive Assailant", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "B"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.b.BlitzwingAdaptiveAssailant.class; + + // Blitzwing, Cruel Tormentor + this.getLeftHalfCard().setPT(6, 5); // More Than Meets the Eye {3}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{B}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{B}")); // At the beginning of your end step, target opponent loses life equal to the life that player lost this turn. If no life is lost this way, convert Blitzwing. Ability ability = new BeginningOfEndStepTriggeredAbility( new BlitzwingCruelTormentorEffect() ); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Blitzwing Adaptive Assailant + this.getRightHalfCard().setPT(3, 5); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // At the beginning of combat on your turn, choose flying or indestructible at random. Blitzwing gains that ability until end of turn. + this.getRightHalfCard().addAbility(new BeginningOfCombatTriggeredAbility( + new BlitzwingAdaptiveAssailantEffect() + )); + + // Whenever Blitzwing deals combat damage to a player, convert it. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new TransformSourceEffect().setText("convert it"), false + )); } private BlitzwingCruelTormentor(final BlitzwingCruelTormentor card) { @@ -81,3 +105,28 @@ class BlitzwingCruelTormentorEffect extends OneShotEffect { return permanent != null && permanent.transform(source, game); } } + +class BlitzwingAdaptiveAssailantEffect extends OneShotEffect { + + BlitzwingAdaptiveAssailantEffect() { + super(Outcome.Benefit); + staticText = "choose flying or indestructible at random. {this} gains that ability until end of turn"; + } + + private BlitzwingAdaptiveAssailantEffect(final BlitzwingAdaptiveAssailantEffect effect) { + super(effect); + } + + @Override + public BlitzwingAdaptiveAssailantEffect copy() { + return new BlitzwingAdaptiveAssailantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Ability ability = RandomUtil.nextBoolean() ? FlyingAbility.getInstance() : IndestructibleAbility.getInstance(); + game.informPlayers(ability.getRule() + " has been chosen"); + game.addEffect(new GainAbilitySourceEffect(ability, Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BloodMoon.java b/Mage.Sets/src/mage/cards/b/BloodMoon.java index 40b3f9a2b23..04ef447040d 100644 --- a/Mage.Sets/src/mage/cards/b/BloodMoon.java +++ b/Mage.Sets/src/mage/cards/b/BloodMoon.java @@ -1,16 +1,10 @@ package mage.cards.b; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.mana.RedManaAbility; +import mage.abilities.effects.common.continuous.NonbasicLandsAreMountainsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.CardType; import java.util.UUID; @@ -23,7 +17,7 @@ public final class BloodMoon extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Nonbasic lands are Mountains. - this.addAbility(new SimpleStaticAbility(new BloodMoonEffect())); + this.addAbility(new SimpleStaticAbility(new NonbasicLandsAreMountainsEffect())); } private BloodMoon(final BloodMoon card) { @@ -34,57 +28,4 @@ public final class BloodMoon extends CardImpl { public BloodMoon copy() { return new BloodMoon(this); } - - static class BloodMoonEffect extends ContinuousEffectImpl { - - private static final FilterLandPermanent filter = new FilterLandPermanent(); - - static { - filter.add(Predicates.not(SuperType.BASIC.getPredicate())); - } - - BloodMoonEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - this.staticText = "Nonbasic lands are Mountains"; - this.dependencyTypes.add(DependencyType.BecomeMountain); - this.dependendToTypes.add(DependencyType.BecomeNonbasicLand); - } - - private BloodMoonEffect(final BloodMoonEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public BloodMoonEffect copy() { - return new BloodMoonEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - switch (layer) { - case TypeChangingEffects_4: - // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects - // So the ability removing has to be done before Layer 6 - // Lands have their mana ability intrinsically, so that is added in layer 4 - land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType); - land.addSubType(game, SubType.MOUNTAIN); - land.removeAllAbilities(source.getSourceId(), game); - land.addAbility(new RedManaAbility(), source.getSourceId(), game); - break; - } - } - return true; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.TypeChangingEffects_4; - } - } } diff --git a/Mage.Sets/src/mage/cards/b/BloodbatSummoner.java b/Mage.Sets/src/mage/cards/b/BloodbatSummoner.java deleted file mode 100644 index 4491fd40c12..00000000000 --- a/Mage.Sets/src/mage/cards/b/BloodbatSummoner.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; -import mage.abilities.keyword.FlyingAbility; -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.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.permanent.token.custom.CreatureToken; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BloodbatSummoner extends CardImpl { - - private static final FilterPermanent filter - = new FilterControlledPermanent(SubType.BLOOD, "Blood token you control"); - - static { - filter.add(TokenPredicate.TRUE); - } - - public BloodbatSummoner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // At the beginning of combat on your turn, up to one target Blood token you control becomes a 2/2 black Bat creature with flying and haste in addition to its other types. - Ability ability = new BeginningOfCombatTriggeredAbility(new BecomesCreatureTargetEffect( - new CreatureToken(2, 2, "", SubType.BAT) - .withAbility(FlyingAbility.getInstance()) - .withAbility(HasteAbility.getInstance()) - .withColor("B"), - false, false, Duration.Custom - ).setText("up to one target Blood token you control becomes a " + - "2/2 black Bat creature with flying and haste in addition to its other types")); - ability.addTarget(new TargetPermanent(0, 1, filter)); - this.addAbility(ability); - } - - private BloodbatSummoner(final BloodbatSummoner card) { - super(card); - } - - @Override - public BloodbatSummoner copy() { - return new BloodbatSummoner(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/Bloodbriar.java b/Mage.Sets/src/mage/cards/b/Bloodbriar.java index c6792f5d9cb..859346ea148 100644 --- a/Mage.Sets/src/mage/cards/b/Bloodbriar.java +++ b/Mage.Sets/src/mage/cards/b/Bloodbriar.java @@ -9,32 +9,24 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import java.util.UUID; /** - * * @author LevelX2 */ public final class Bloodbriar extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public Bloodbriar(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, SubType.ELEMENTAL); this.power = new MageInt(2); this.toughness = new MageInt(3); // Whenever you sacrifice another permanent, put a +1/+1 counter on Bloodbriar. this.addAbility(new SacrificePermanentTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT )); } diff --git a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java index 8cc8653d882..8a0186c8386 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineKeeper.java @@ -1,9 +1,8 @@ - package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; @@ -11,17 +10,19 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.VampireToken; import java.util.UUID; @@ -29,33 +30,46 @@ import java.util.UUID; /** * @author Loki */ -public final class BloodlineKeeper extends CardImpl { +public final class BloodlineKeeper extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent(SubType.VAMPIRE, "you control five or more Vampires"); private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4); private static final Hint hint = new ValueHint("Vampires you control", new PermanentsOnBattlefieldCount(filter)); + private static final FilterCreaturePermanent lordOfLineageFilter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampire creatures"); public BloodlineKeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{B}{B}", + "Lord of Lineage", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B"); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + // Bloodline Keeper + this.getLeftHalfCard().setPT(3, 3); - this.secondSideCardClazz = mage.cards.l.LordOfLineage.class; - - this.addAbility(FlyingAbility.getInstance()); + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // {T}: Create a 2/2 black Vampire creature token with flying. - this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); // {B}: Transform Bloodline Keeper. Activate this ability only if you control five or more Vampires. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{B}"), condition ).addHint(hint)); + + // Lord of Lineage + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Other Vampire creatures you control get +2/+2. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, lordOfLineageFilter, true))); + + // {T}: Create a 2/2 black Vampire creature token with flying. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); + } private BloodlineKeeper(final BloodlineKeeper card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodmarkMentor.java b/Mage.Sets/src/mage/cards/b/BloodmarkMentor.java index d4c66fc0db1..b31fc196330 100644 --- a/Mage.Sets/src/mage/cards/b/BloodmarkMentor.java +++ b/Mage.Sets/src/mage/cards/b/BloodmarkMentor.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; @@ -12,17 +10,19 @@ 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 java.util.UUID; + /** * * @author North */ public final class BloodmarkMentor extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Red creatures"); + private static final FilterPermanent filter = new FilterCreaturePermanent("Red creatures"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/b/BloodsoakedReveler.java b/Mage.Sets/src/mage/cards/b/BloodsoakedReveler.java deleted file mode 100644 index 1c5d37419f5..00000000000 --- a/Mage.Sets/src/mage/cards/b/BloodsoakedReveler.java +++ /dev/null @@ -1,64 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.YouGainedLifeCondition; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.game.permanent.token.BloodToken; -import mage.watchers.common.PlayerGainedLifeWatcher; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BloodsoakedReveler extends CardImpl { - - private static final Condition condition = new YouGainedLifeCondition(); - private static final Hint hint = new ConditionHint(condition, "You gained life this turn"); - - public BloodsoakedReveler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // At the beginning of your end step, if you gained life this turn, create a Blood token. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.YOU, new CreateTokenEffect(new BloodToken()), - false, condition - ).addHint(hint), new PlayerGainedLifeWatcher()); - - // {4}{B}: Each opponent loses 2 life and you gain 2 life. - Ability ability = new SimpleActivatedAbility( - new LoseLifeOpponentsEffect(2), new ManaCostsImpl<>("{4}{B}") - ); - ability.addEffect(new GainLifeEffect(2).concatBy("and")); - this.addAbility(ability); - } - - private BloodsoakedReveler(final BloodsoakedReveler card) { - super(card); - } - - @Override - public BloodsoakedReveler copy() { - return new BloodsoakedReveler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BloodswornKnight.java b/Mage.Sets/src/mage/cards/b/BloodswornKnight.java deleted file mode 100644 index ac11ba87537..00000000000 --- a/Mage.Sets/src/mage/cards/b/BloodswornKnight.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.TapSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.IndestructibleAbility; -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 java.util.UUID; - -/** - * @author weirddan455 - */ -public final class BloodswornKnight extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURES); - - public BloodswornKnight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setBlack(true); - - // Back half of Bloodsworn Squire - this.nightCard = true; - - // Bloodsworn Knight's power and toughness are each equal to the number of creature cards in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); - - // {1}{B}, Discard a card: Bloodsworn Knight gains indestructible until end of turn. Tap it. - Ability ability = new SimpleActivatedAbility( - new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), - new ManaCostsImpl<>("{1}{B}") - ); - ability.addCost(new DiscardCardCost()); - ability.addEffect(new TapSourceEffect().setText("tap it")); - this.addAbility(ability); - } - - private BloodswornKnight(final BloodswornKnight card) { - super(card); - } - - @Override - public BloodswornKnight copy() { - return new BloodswornKnight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BloodswornSquire.java b/Mage.Sets/src/mage/cards/b/BloodswornSquire.java index a13ac16a0a7..024c1363925 100644 --- a/Mage.Sets/src/mage/cards/b/BloodswornSquire.java +++ b/Mage.Sets/src/mage/cards/b/BloodswornSquire.java @@ -1,41 +1,45 @@ package mage.cards.b; -import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TransformAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; +import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class BloodswornSquire extends CardImpl { +public final class BloodswornSquire extends TransformingDoubleFacedCard { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURES); public BloodswornSquire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.SOLDIER}, "{3}{B}", + "Bloodsworn Knight", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.KNIGHT}, "B"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BloodswornKnight.class; - - this.addAbility(new TransformAbility()); + // Bloodsworn Squire + this.getLeftHalfCard().setPT(3, 3); // {1}{B}, Discard a card: Bloodsworn Squire gains indestructible until end of turn. Tap it. Then if there are four or more creature cards in your graveyard, transform Bloodsworn Squire. Ability ability = new SimpleActivatedAbility( @@ -49,7 +53,22 @@ public final class BloodswornSquire extends CardImpl { new CardsInControllerGraveyardCondition(4, StaticFilters.FILTER_CARD_CREATURES), "Then if there are four or more creature cards in your graveyard, transform {this}" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Bloodsworn Knight + this.getRightHalfCard().setPT(0, 0); + + // Bloodsworn Knight's power and toughness are each equal to the number of creature cards in your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); + + // {1}{B}, Discard a card: Bloodsworn Knight gains indestructible until end of turn. Tap it. + ability = new SimpleActivatedAbility( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), + new ManaCostsImpl<>("{1}{B}") + ); + ability.addCost(new DiscardCardCost()); + ability.addEffect(new TapSourceEffect().setText("tap it")); + this.getRightHalfCard().addAbility(ability); } private BloodswornSquire(final BloodswornSquire card) { diff --git a/Mage.Sets/src/mage/cards/b/BloomwielderDryads.java b/Mage.Sets/src/mage/cards/b/BloomwielderDryads.java deleted file mode 100644 index e3782f4aedc..00000000000 --- a/Mage.Sets/src/mage/cards/b/BloomwielderDryads.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.WardAbility; -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 BloomwielderDryads extends CardImpl { - - public BloomwielderDryads(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DRYAD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setGreen(true); - this.nightCard = true; - - // Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); - - // At the beginning of your end step, put a +1/+1 counter on target creature you control. - Ability ability = new BeginningOfEndStepTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - ); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); - } - - private BloomwielderDryads(final BloomwielderDryads card) { - super(card); - } - - @Override - public BloomwielderDryads copy() { - return new BloomwielderDryads(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BlossomCladWerewolf.java b/Mage.Sets/src/mage/cards/b/BlossomCladWerewolf.java deleted file mode 100644 index 39737df7b9d..00000000000 --- a/Mage.Sets/src/mage/cards/b/BlossomCladWerewolf.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.mana.SimpleManaAbility; -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 BlossomCladWerewolf extends CardImpl { - - public BlossomCladWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setGreen(true); - this.nightCard = true; - - // {T}: Add two mana of any one color. - this.addAbility(new SimpleManaAbility( - Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost() - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private BlossomCladWerewolf(final BlossomCladWerewolf card) { - super(card); - } - - @Override - public BlossomCladWerewolf copy() { - return new BlossomCladWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BoarQPine.java b/Mage.Sets/src/mage/cards/b/BoarQPine.java new file mode 100644 index 00000000000..fa7588a24df --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoarQPine.java @@ -0,0 +1,43 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoarQPine extends CardImpl { + + public BoarQPine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.BOAR); + this.subtype.add(SubType.PORCUPINE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a noncreature spell, put a +1/+1 counter on this creature. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + } + + private BoarQPine(final BoarQPine card) { + super(card); + } + + @Override + public BoarQPine copy() { + return new BoarQPine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoilingRockPrison.java b/Mage.Sets/src/mage/cards/b/BoilingRockPrison.java new file mode 100644 index 00000000000..7947b1b9b76 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoilingRockPrison.java @@ -0,0 +1,48 @@ +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.GenericManaCost; +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 BoilingRockPrison extends CardImpl { + + public BoilingRockPrison(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {B} or {R}. + this.addAbility(new BlackManaAbility()); + this.addAbility(new RedManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private BoilingRockPrison(final BoilingRockPrison card) { + super(card); + } + + @Override + public BoilingRockPrison copy() { + return new BoilingRockPrison(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java b/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java new file mode 100644 index 00000000000..117abeba8e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoilingRockRioter.java @@ -0,0 +1,104 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.keyword.FirebendingAbility; +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.filter.FilterCard; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoilingRockRioter extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.ALLY, "untapped Ally you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + + public BoilingRockRioter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // Tap an untapped Ally you control: Exile target card from a graveyard. + Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new TapTargetCost(filter)); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + + // Whenever this creature attacks, you may cast an Ally spell from among cards you own exiled with this creature. + this.addAbility(new AttacksTriggeredAbility(new BoilingRockRioterEffect())); + } + + private BoilingRockRioter(final BoilingRockRioter card) { + super(card); + } + + @Override + public BoilingRockRioter copy() { + return new BoilingRockRioter(this); + } +} + +class BoilingRockRioterEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(SubType.ALLY); + + BoilingRockRioterEffect() { + super(Outcome.Benefit); + staticText = "you may cast an Ally spell from among cards you own exiled with this creature"; + } + + private BoilingRockRioterEffect(final BoilingRockRioterEffect effect) { + super(effect); + } + + @Override + public BoilingRockRioterEffect copy() { + return new BoilingRockRioterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = Optional + .ofNullable(CardUtil.getExileZoneId(game, source)) + .map(game.getExile()::getExileZone) + .map(CardsImpl::new) + .orElseGet(CardsImpl::new); + cards.removeIf(uuid -> !source.isControlledBy(game.getOwnerId(uuid))); + return CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BondedConstruct.java b/Mage.Sets/src/mage/cards/b/BondedConstruct.java index f8637ea0bb6..1a9aecd8719 100644 --- a/Mage.Sets/src/mage/cards/b/BondedConstruct.java +++ b/Mage.Sets/src/mage/cards/b/BondedConstruct.java @@ -1,28 +1,29 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BondedConstruct extends CardImpl { public BondedConstruct(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(2); this.toughness = new MageInt(1); // Bonded Construct can't attack alone. - this.addAbility(new CantAttackAloneAbility()); + this.addAbility(new SimpleStaticAbility(new CantAttackAloneSourceEffect())); } private BondedConstruct(final BondedConstruct card) { diff --git a/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java b/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java index aa422331237..205bd40eae0 100644 --- a/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java +++ b/Mage.Sets/src/mage/cards/b/BondedHerdbeast.java @@ -1,12 +1,11 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,19 +14,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BondedHerdbeast extends CardImpl { +public final class BondedHerdbeast extends TransformingDoubleFacedCard { public BondedHerdbeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BEAST}, "{4}{G}", + "Plated Kilnbeast", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.BEAST}, "RG"); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.p.PlatedKilnbeast.class; + // Bonded Herdbeast + this.getLeftHalfCard().setPT(4, 5); // {4}{R/P}: Transform Bonded Herdbeast. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R/P}"))); + + // Plated Kilnbeast + this.getRightHalfCard().setPT(7, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); } private BondedHerdbeast(final BondedHerdbeast card) { diff --git a/Mage.Sets/src/mage/cards/b/BondedHorncrest.java b/Mage.Sets/src/mage/cards/b/BondedHorncrest.java index d2937895a95..0c1435af99f 100644 --- a/Mage.Sets/src/mage/cards/b/BondedHorncrest.java +++ b/Mage.Sets/src/mage/cards/b/BondedHorncrest.java @@ -1,14 +1,14 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; -import mage.constants.SubType; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; /** * @@ -24,8 +24,7 @@ public final class BondedHorncrest extends CardImpl { this.toughness = new MageInt(5); // Bonded Horncrest can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private BondedHorncrest(final BondedHorncrest card) { diff --git a/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java index c20f2a16940..8fc5ea889d1 100644 --- a/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java +++ b/Mage.Sets/src/mage/cards/b/BonecrusherGiant.java @@ -29,9 +29,8 @@ public final class BonecrusherGiant extends AdventureCard { // Whenever Bonecrusher Giant becomes the target of a spell, Bonecrusher Giant deals 2 damage to that spell's controller. this.addAbility(new BecomesTargetSourceTriggeredAbility( - new DamageTargetEffect( - 2, true, "that spell's controller", "{this}" - ), StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false) + new DamageTargetEffect(2).withTargetDescription("that spell's controller"), + StaticFilters.FILTER_SPELL_A, SetTargetPointer.PLAYER, false) .withRuleTextReplacement(false)); // Stomp diff --git a/Mage.Sets/src/mage/cards/b/BoobyTrap.java b/Mage.Sets/src/mage/cards/b/BoobyTrap.java index e26b8ebf1af..2cec841bf46 100644 --- a/Mage.Sets/src/mage/cards/b/BoobyTrap.java +++ b/Mage.Sets/src/mage/cards/b/BoobyTrap.java @@ -51,8 +51,11 @@ public final class BoobyTrap extends CardImpl { class BoobyTrapTriggeredAbility extends TriggeredAbilityImpl { - public BoobyTrapTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new DamageTargetEffect(10, true, "that player"), new SacrificeSourceCost(), "", false), false); + BoobyTrapTriggeredAbility() { + super(Zone.BATTLEFIELD, new DoIfCostPaid( + new DamageTargetEffect(10).withTargetDescription("that player"), + new SacrificeSourceCost(), "", false + ), false); } private BoobyTrapTriggeredAbility(final BoobyTrapTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/b/BoomerangBasics.java b/Mage.Sets/src/mage/cards/b/BoomerangBasics.java new file mode 100644 index 00000000000..29594aa5e7b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoomerangBasics.java @@ -0,0 +1,74 @@ +package mage.cards.b; + +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.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoomerangBasics extends CardImpl { + + public BoomerangBasics(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + this.subtype.add(SubType.LESSON); + + // Return target nonland permanent to its owner's hand. If you controlled that permanent, draw a card. + this.getSpellAbility().addEffect(new BoomerangBasicsEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private BoomerangBasics(final BoomerangBasics card) { + super(card); + } + + @Override + public BoomerangBasics copy() { + return new BoomerangBasics(this); + } +} + +class BoomerangBasicsEffect extends OneShotEffect { + + BoomerangBasicsEffect() { + super(Outcome.Benefit); + staticText = "return target nonland permanent to its owner's hand. If you controlled that permanent, draw a card"; + } + + private BoomerangBasicsEffect(final BoomerangBasicsEffect effect) { + super(effect); + } + + @Override + public BoomerangBasicsEffect copy() { + return new BoomerangBasicsEffect(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; + } + boolean flag = permanent.isControlledBy(player.getId()); + player.moveCards(permanent, Zone.HAND, source, game); + if (flag) { + game.processAction(); + player.drawCards(1, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoscoJustABear.java b/Mage.Sets/src/mage/cards/b/BoscoJustABear.java new file mode 100644 index 00000000000..9fd115d629f --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoscoJustABear.java @@ -0,0 +1,67 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +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.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoscoJustABear extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY); + private static final Hint hint = new ValueHint("Legendary creatures you control", xValue); + + public BoscoJustABear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Bosco enters, create a Food token for each legendary creature you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken(), xValue)).addHint(hint)); + + // {2}{G}, Sacrifice a Food: Put two +1/+1 counters on Bosco. He gains trample until end of turn. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ManaCostsImpl<>("{2}{G}") + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_FOOD)); + ability.addEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("He gains trample until end of turn")); + this.addAbility(ability); + } + + private BoscoJustABear(final BoscoJustABear card) { + super(card); + } + + @Override + public BoscoJustABear copy() { + return new BoscoJustABear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java index 120cf07a3ab..7e5bc35d11a 100644 --- a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java +++ b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java @@ -1,13 +1,17 @@ package mage.cards.b; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.ReachAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; import mage.filter.FilterCard; @@ -21,22 +25,23 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BoseijuReachesSkyward extends CardImpl { +public final class BoseijuReachesSkyward extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards"); public BoseijuReachesSkyward(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.b.BranchOfBoseiju.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{G}", + "Branch of Boseiju", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.PLANT}, "G"); + // Boseiju Reaches Skyward // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(getLeftHalfCard()); // I — Search your library for up to two basic Forest cards, reveal them, put them into your hand, then shuffle. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, + getLeftHalfCard(), SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect(new TargetCardInLibrary( 0, 2, filter ), true) @@ -44,16 +49,25 @@ public final class BoseijuReachesSkyward extends CardImpl { // II — Put up to one target land card from your graveyard on top of your library. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new PutOnLibraryTargetEffect(true), new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_LAND_FROM_YOUR_GRAVEYARD) ); // 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()); + sagaAbility.addChapterEffect(getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Branch of Boseiju + this.getRightHalfCard().setPT(0, 0); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Branch of Boseiju gets +1/+1 for each land you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostSourceEffect( + LandsYouControlCount.instance, LandsYouControlCount.instance, Duration.WhileOnBattlefield + ).setText("{this} gets +1/+1 for each land you control"))); } private BoseijuReachesSkyward(final BoseijuReachesSkyward card) { diff --git a/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java b/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java new file mode 100644 index 00000000000..40ea7ba49ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BottomlessPoolLockerRoom.java @@ -0,0 +1,54 @@ +package mage.cards.b; + +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author oscscull + */ +public final class BottomlessPoolLockerRoom extends RoomCard { + + public BottomlessPoolLockerRoom(UUID ownerId, CardSetInfo setInfo) { + // Bottomless Pool + // {U} + // When you unlock this door, return up to one target creature to its owner’s hand. + // Locker Room + // {4}{U} + // Enchantment -- Room + // Whenever one or more creatures you control deal combat damage to a player, draw a card. + super(ownerId, setInfo, + "{U}", "{4}{U}"); + this.subtype.add(SubType.ROOM); + + // Left half ability - "When you unlock this door, return up to one target creature to its owner’s hand." + UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility( + new ReturnToHandTargetEffect(), false, true); + left.addTarget(new TargetCreaturePermanent(0, 1)); + this.getLeftHalfCard().addAbility(left); + + // Right half ability - "Whenever one or more creatures you control deal combat damage to a player, draw a card." + DealsDamageToAPlayerAllTriggeredAbility right = new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + StaticFilters.FILTER_CONTROLLED_A_CREATURE, + false, SetTargetPointer.PLAYER, true, true, TargetController.OPPONENT); + this.getRightHalfCard().addAbility(right); + } + + private BottomlessPoolLockerRoom(final BottomlessPoolLockerRoom card) { + super(card); + } + + @Override + public BottomlessPoolLockerRoom copy() { + return new BottomlessPoolLockerRoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BraceForImpact.java b/Mage.Sets/src/mage/cards/b/BraceForImpact.java index 68e94370dd2..270f1af5ff0 100644 --- a/Mage.Sets/src/mage/cards/b/BraceForImpact.java +++ b/Mage.Sets/src/mage/cards/b/BraceForImpact.java @@ -1,6 +1,7 @@ package mage.cards.b; import mage.abilities.Ability; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,13 +11,9 @@ import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.MulticoloredPredicate; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -67,26 +64,15 @@ 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)) { - 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) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 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()); + targetPermanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); } + return false; } - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BraidedNet.java b/Mage.Sets/src/mage/cards/b/BraidedNet.java index 1457bd6054b..c6cb8b39632 100644 --- a/Mage.Sets/src/mage/cards/b/BraidedNet.java +++ b/Mage.Sets/src/mage/cards/b/BraidedNet.java @@ -5,20 +5,28 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; @@ -26,7 +34,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BraidedNet extends CardImpl { +public final class BraidedNet extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent"); @@ -35,11 +43,14 @@ public final class BraidedNet extends CardImpl { } public BraidedNet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); - this.secondSideCardClazz = mage.cards.b.BraidedQuipu.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{U}", + "Braided Quipu", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U"); + // Braided Net // Braided Net enters the battlefield with three net counters on it. - this.addAbility(new EntersBattlefieldAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.NET.createInstance(3)), "with three net counters on it" )); @@ -49,10 +60,20 @@ public final class BraidedNet extends CardImpl { ability.addCost(new RemoveCountersSourceCost(CounterType.NET.createInstance())); ability.addEffect(new BraidedNetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {1}{U} - this.addAbility(new CraftAbility("{1}{U}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{1}{U}")); + + // Braided Quipu + // {3}{U}, {T}: Draw a card for each artifact you control, then put Braided Quipu into its owner's library third from the top. + ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(ArtifactYouControlCount.instance), new ManaCostsImpl<>("{3}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addEffect(new BraidedQuipuEffect()); + this.getRightHalfCard().addAbility(ability.addHint(ArtifactYouControlHint.instance)); + } private BraidedNet(final BraidedNet card) { @@ -100,3 +121,29 @@ class BraidedNetEffect extends RestrictionEffect { return permanent == null || !permanent.isTapped(); } } + +class BraidedQuipuEffect extends OneShotEffect { + + BraidedQuipuEffect() { + super(Outcome.Benefit); + staticText = ", then put {this} into its owner's library third from the top"; + } + + private BraidedQuipuEffect(final BraidedQuipuEffect effect) { + super(effect); + } + + @Override + public BraidedQuipuEffect copy() { + return new BraidedQuipuEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return player != null + && permanent != null + && player.putCardOnTopXOfLibrary(permanent, game, source, 3, true); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BraidedQuipu.java b/Mage.Sets/src/mage/cards/b/BraidedQuipu.java deleted file mode 100644 index e68735e4d47..00000000000 --- a/Mage.Sets/src/mage/cards/b/BraidedQuipu.java +++ /dev/null @@ -1,74 +0,0 @@ -package mage.cards.b; - -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.ArtifactYouControlCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.hint.common.ArtifactYouControlHint; -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.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BraidedQuipu extends CardImpl { - - public BraidedQuipu(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - this.color.setBlue(true); - - // {3}{U}, {T}: Draw a card for each artifact you control, then put Braided Quipu into its owner's library third from the top. - Ability ability = new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(ArtifactYouControlCount.instance), new ManaCostsImpl<>("{3}{U}") - ); - ability.addCost(new TapSourceCost()); - ability.addEffect(new BraidedQuipuEffect()); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); - } - - private BraidedQuipu(final BraidedQuipu card) { - super(card); - } - - @Override - public BraidedQuipu copy() { - return new BraidedQuipu(this); - } -} - -class BraidedQuipuEffect extends OneShotEffect { - - BraidedQuipuEffect() { - super(Outcome.Benefit); - staticText = ", then put {this} into its owner's library third from the top"; - } - - private BraidedQuipuEffect(final BraidedQuipuEffect effect) { - super(effect); - } - - @Override - public BraidedQuipuEffect copy() { - return new BraidedQuipuEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - return player != null - && permanent != null - && player.putCardOnTopXOfLibrary(permanent, game, source, 3, true); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java b/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java deleted file mode 100644 index 7f721738d42..00000000000 --- a/Mage.Sets/src/mage/cards/b/BranchOfBoseiju.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.LandsYouControlCount; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BranchOfBoseiju extends CardImpl { - - public BranchOfBoseiju(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.PLANT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Branch of Boseiju gets +1/+1 for each land you control. - this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( - LandsYouControlCount.instance, LandsYouControlCount.instance, Duration.WhileOnBattlefield - ).setText("{this} gets +1/+1 for each land you control"))); - } - - private BranchOfBoseiju(final BranchOfBoseiju card) { - super(card); - } - - @Override - public BranchOfBoseiju copy() { - return new BranchOfBoseiju(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrandedHowler.java b/Mage.Sets/src/mage/cards/b/BrandedHowler.java deleted file mode 100644 index 4aac4619373..00000000000 --- a/Mage.Sets/src/mage/cards/b/BrandedHowler.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.b; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class BrandedHowler extends CardImpl { - - public BrandedHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Branded Howler. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private BrandedHowler(final BrandedHowler card) { - super(card); - } - - @Override - public BrandedHowler copy() { - return new BrandedHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BraskasFinalAeon.java b/Mage.Sets/src/mage/cards/b/BraskasFinalAeon.java deleted file mode 100644 index a59cb3fc942..00000000000 --- a/Mage.Sets/src/mage/cards/b/BraskasFinalAeon.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.SacrificeOpponentsEffect; -import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BraskasFinalAeon extends CardImpl { - - public BraskasFinalAeon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.NIGHTMARE); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.nightCard = true; - this.color.setBlack(true); - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Jecht Beam -- Each opponent discards a card and you draw a card. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { - ability.addEffect(new DiscardEachPlayerEffect(TargetController.OPPONENT)); - ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and you")); - ability.withFlavorWord("Jecht Beam"); - }); - - // III -- Ultimate Jecht Shot -- Each opponent sacrifices two creatures of their choice. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new SacrificeOpponentsEffect(2, StaticFilters.FILTER_PERMANENT_CREATURES)); - ability.withFlavorWord("Ultimate Jecht Shot"); - }); - this.addAbility(sagaAbility.withShowSacText(true)); - - // Menace - this.addAbility(new MenaceAbility()); - } - - private BraskasFinalAeon(final BraskasFinalAeon card) { - super(card); - } - - @Override - public BraskasFinalAeon copy() { - return new BraskasFinalAeon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java index 16459284827..1c9bc9ec276 100644 --- a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java +++ b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java @@ -1,6 +1,7 @@ package mage.cards.b; import mage.abilities.Ability; +import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.DescendedThisTurnCondition; @@ -11,16 +12,17 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.keyword.DiscoverEffect; +import mage.abilities.mana.RedManaAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.PermanentPredicate; import mage.game.Game; +import mage.game.stack.Spell; import mage.players.Player; import mage.watchers.common.DescendedWatcher; @@ -29,21 +31,27 @@ import java.util.UUID; /** * @author Susucr */ -public final class BrasssTunnelGrinder extends CardImpl { +public final class BrasssTunnelGrinder extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.BORE, 3); + private static final FilterSpell filter = new FilterSpell("a permanent spell"); + + static { + filter.add(PermanentPredicate.instance); + } + public BrasssTunnelGrinder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); - this.secondSideCardClazz = mage.cards.t.TecutlanTheSearingRift.class; - - this.supertype.add(SuperType.LEGENDARY); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{R}", + "Tecutlan, the Searing Rift", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, ""); + // Brass's Tunnel-Grinder // When Brass's Tunnel-Grinder enters the battlefield, discard any number of cards, then draw that many cards plus one. - this.addAbility(new EntersBattlefieldTriggeredAbility(new BrasssTunnelGrinderEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new BrasssTunnelGrinderEffect())); // At the beginning of your end step, if you descended this turn, put a bore counter on Brass's Tunnel-Grinder. Then if there are three or more bore counters on it, remove those counters and transform it. - this.addAbility(new TransformAbility()); Ability ability = new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new AddCountersSourceEffect(CounterType.BORE.createInstance()), false, DescendedThisTurnCondition.instance @@ -53,7 +61,18 @@ public final class BrasssTunnelGrinder extends CardImpl { "Then if there are three or more bore counters on it, remove those counters and transform it" ).addEffect(new TransformSourceEffect())); ability.addHint(DescendedThisTurnCount.getHint()); - this.addAbility(ability, new DescendedWatcher()); + ability.addWatcher(new DescendedWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Tecutlan, the Searing Rift + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); + + // Whenever you cast a permanent spell using mana produced by Tecutlan, the Searing Rift, discover X, where X is that spell's mana value. + this.getRightHalfCard().addAbility(new CastSpellPaidBySourceTriggeredAbility( + new TecutlanTheSearingRiftEffect(), + filter, true + )); } private BrasssTunnelGrinder(final BrasssTunnelGrinder card) { @@ -94,3 +113,35 @@ class BrasssTunnelGrinderEffect extends OneShotEffect { return true; } } + +class TecutlanTheSearingRiftEffect extends OneShotEffect { + + TecutlanTheSearingRiftEffect() { + super(Outcome.Benefit); + staticText = "discover X, where X is that spell's mana value"; + } + + private TecutlanTheSearingRiftEffect(final TecutlanTheSearingRiftEffect effect) { + super(effect); + } + + @Override + public TecutlanTheSearingRiftEffect copy() { + return new TecutlanTheSearingRiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); + int mv = spell == null ? 0 : Math.max(0, spell.getManaValue()); + + DiscoverEffect.doDiscover(controller, mv, game, source); + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/b/BreakneckRider.java b/Mage.Sets/src/mage/cards/b/BreakneckRider.java index fbc0c3322e3..216c81bab3e 100644 --- a/Mage.Sets/src/mage/cards/b/BreakneckRider.java +++ b/Mage.Sets/src/mage/cards/b/BreakneckRider.java @@ -1,31 +1,54 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author fireshoes */ -public final class BreakneckRider extends CardImpl { +public final class BreakneckRider extends TransformingDoubleFacedCard { public BreakneckRider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); - this.subtype.add(SubType.HUMAN, SubType.SCOUT, SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SCOUT, SubType.WEREWOLF}, "{1}{R}{R}", + "Neck Breaker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.n.NeckBreaker.class; + // Breakneck Rider + this.getLeftHalfCard().setPT(3, 3); // At the beginning of each upkeep, if no spells were cast last turn, transform Breakneck Rider. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Neck Breaker + this.getRightHalfCard().setPT(4, 3); + + // Attacking creatures you control get +1/+0 and have trample. + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, + StaticFilters.FILTER_ATTACKING_CREATURES + )); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_ATTACKING_CREATURES + ).setText("and have trample")); + this.getRightHalfCard().addAbility(ability); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Neck Breaker. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private BreakneckRider(final BreakneckRider card) { diff --git a/Mage.Sets/src/mage/cards/b/BrineComber.java b/Mage.Sets/src/mage/cards/b/BrineComber.java index 084f01247f6..9bcbd692ed0 100644 --- a/Mage.Sets/src/mage/cards/b/BrineComber.java +++ b/Mage.Sets/src/mage/cards/b/BrineComber.java @@ -1,26 +1,28 @@ package mage.cards.b; -import mage.MageInt; +import mage.abilities.common.BecomesTargetAttachedTriggeredAbility; import mage.abilities.common.BecomesTargetSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; 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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.predicate.other.AuraSpellPredicate; import mage.game.permanent.token.SpiritWhiteToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class BrineComber extends CardImpl { +public final class BrineComber extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("an Aura spell"); @@ -29,21 +31,40 @@ public final class BrineComber extends CardImpl { } public BrineComber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{1}{W}{U}", + "Brinebound Gift", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "WU"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.b.BrineboundGift.class; + // Brine Comber + this.getLeftHalfCard().setPT(1, 1); // Whenever Brine Comber enters the battlefield or becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. - this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, + this.getLeftHalfCard().addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, "Whenever {this} enters or becomes the target of an Aura spell, ", new EntersBattlefieldTriggeredAbility(null), new BecomesTargetSourceTriggeredAbility(null, filter))); + + // Brinebound Gift + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {W}{U} - this.addAbility(new DisturbAbility(this, "{W}{U}")); + // needs to be added after enchant ability is set for target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{W}{U}")); + + // Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. + this.getRightHalfCard().addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, + "Whenever {this} enters or enchanted creature becomes the target of an Aura spell, ", + new EntersBattlefieldTriggeredAbility(null), + new BecomesTargetAttachedTriggeredAbility(null, filter, SetTargetPointer.NONE, false))); + + // If Brinebound Gift would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private BrineComber(final BrineComber card) { diff --git a/Mage.Sets/src/mage/cards/b/BrineboundGift.java b/Mage.Sets/src/mage/cards/b/BrineboundGift.java deleted file mode 100644 index 254ed7f3601..00000000000 --- a/Mage.Sets/src/mage/cards/b/BrineboundGift.java +++ /dev/null @@ -1,64 +0,0 @@ -package mage.cards.b; - -import mage.abilities.common.BecomesTargetAttachedTriggeredAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.meta.OrTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterSpell; -import mage.filter.predicate.other.AuraSpellPredicate; -import mage.game.permanent.token.SpiritWhiteToken; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class BrineboundGift extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("an Aura spell"); - - static { - filter.add(AuraSpellPredicate.instance); - } - - public BrineboundGift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Whenever Brinebound Gift enters the battlefield or enchanted creature becomes the target of an Aura spell, create a 1/1 white Spirit creature token with flying. - this.addAbility(new OrTriggeredAbility(Zone.ALL, new CreateTokenEffect(new SpiritWhiteToken()), false, - "Whenever {this} enters or enchanted creature becomes the target of an Aura spell, ", - new EntersBattlefieldTriggeredAbility(null), - new BecomesTargetAttachedTriggeredAbility(null, filter, SetTargetPointer.NONE, false))); - - // If Brinebound Gift would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private BrineboundGift(final BrineboundGift card) { - super(card); - } - - @Override - public BrineboundGift copy() { - return new BrineboundGift(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrothersOfFire.java b/Mage.Sets/src/mage/cards/b/BrothersOfFire.java index ba5e830dd35..98098bfe433 100644 --- a/Mage.Sets/src/mage/cards/b/BrothersOfFire.java +++ b/Mage.Sets/src/mage/cards/b/BrothersOfFire.java @@ -1,21 +1,18 @@ - package mage.cards.b; -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.Effect; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; 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 LoneFox @@ -29,10 +26,7 @@ public final class BrothersOfFire extends CardImpl { this.toughness = new MageInt(2); // {1}{R}{R}: Brothers of Fire deals 1 damage to any target and 1 damage to you. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}{R}")); - Effect effect = new DamageControllerEffect(1); - effect.setText("and 1 damage to you"); - ability.addEffect(effect); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(1), new ManaCostsImpl<>("{1}{R}{R}")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BruceBanner.java b/Mage.Sets/src/mage/cards/b/BruceBanner.java new file mode 100644 index 00000000000..406068aa95e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BruceBanner.java @@ -0,0 +1,82 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +import mage.abilities.condition.common.SourceAttackingCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.AdditionalCombatPhaseEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardSetInfo; +import mage.cards.ModalDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BruceBanner extends ModalDoubleFacedCard { + + public BruceBanner(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SCIENTIST, SubType.HERO}, "{U}", + "The Incredible Hulk", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GAMMA, SubType.BERSERKER, SubType.HERO}, "{2}{R}{R}{G}{G}" + ); + this.getLeftHalfCard().setPT(1, 1); + this.getRightHalfCard().setPT(8, 8); + + // {X}{X}, {T}: Draw X cards. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new DrawCardSourceControllerEffect(GetXValue.instance), new ManaCostsImpl<>("{X}{X}") + ); + ability.addCost(new TapSourceCost()); + this.getLeftHalfCard().addAbility(ability); + + // {2}{R}{R}{G}{G}: Transform Bruce Banner. Activate only as a sorcery. + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{R}{R}{G}{G}") + )); + + // The Incredible Hulk + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Enrage -- Whenever The Incredible Hulk is dealt damage, put a +1/+1 counter on him. If he's attacking, untap him and there is an additional combat phase after this phase. + ability = new DealtDamageToSourceTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on him"), + false, true + ); + ability.addEffect(new ConditionalOneShotEffect( + new UntapSourceEffect(), SourceAttackingCondition.instance, "If he's attacking, " + + "untap him and there is an additional combat phase after this phase" + ).addEffect(new AdditionalCombatPhaseEffect())); + this.getRightHalfCard().addAbility(ability); + } + + private BruceBanner(final BruceBanner card) { + super(card); + } + + @Override + public BruceBanner copy() { + return new BruceBanner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrutalCathar.java b/Mage.Sets/src/mage/cards/b/BrutalCathar.java index bf58c854a03..44ad7a76194 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalCathar.java +++ b/Mage.Sets/src/mage/cards/b/BrutalCathar.java @@ -1,12 +1,15 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.WardAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetOpponentsCreaturePermanent; @@ -16,17 +19,18 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BrutalCathar extends CardImpl { +public final class BrutalCathar extends TransformingDoubleFacedCard { public BrutalCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER, SubType.WEREWOLF}, "{2}{W}", + "Moonrage Brute", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); + + + // Brutal Cathar + this.getLeftHalfCard().setPT(2, 2); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.m.MoonrageBrute.class; // When this creature enters the battlefield or transforms into Brutal Cathar, exile target creature an opponent controls until this creature leaves the battlefield. Ability ability = new TransformsOrEntersTriggeredAbility( @@ -34,10 +38,22 @@ public final class BrutalCathar extends CardImpl { .setText("exile target creature an opponent controls until this creature leaves the battlefield"), false ).setTriggerPhrase("When this creature enters or transforms into {this}, "); ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Moonrage Brute + this.getRightHalfCard().setPT(3, 3); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Ward—Pay 3 life. + this.getRightHalfCard().addAbility(new WardAbility(new PayLifeCost(3), false)); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BrutalCathar(final BrutalCathar card) { diff --git a/Mage.Sets/src/mage/cards/b/BugenhagenWiseElder.java b/Mage.Sets/src/mage/cards/b/BugenhagenWiseElder.java index 160bde643b4..102d2039927 100644 --- a/Mage.Sets/src/mage/cards/b/BugenhagenWiseElder.java +++ b/Mage.Sets/src/mage/cards/b/BugenhagenWiseElder.java @@ -30,7 +30,7 @@ public final class BugenhagenWiseElder extends CardImpl { = new FilterControlledCreaturePermanent("you control a creature with power 7 or greater"); static { - filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 7)); + filter.add(new PowerPredicate(ComparisonType.OR_GREATER, 7)); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); diff --git a/Mage.Sets/src/mage/cards/b/BumiBash.java b/Mage.Sets/src/mage/cards/b/BumiBash.java new file mode 100644 index 00000000000..345c12521c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BumiBash.java @@ -0,0 +1,56 @@ +package mage.cards.b; + +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BumiBash extends CardImpl { + + private static final FilterPermanent filter = new FilterLandPermanent("land creature or nonbasic land"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + Predicates.not(SuperType.BASIC.getPredicate()) + )); + } + + public BumiBash(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Choose one -- + // * Bumi Bash deals damage equal to the number of lands you control to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(LandsYouControlCount.instance) + .setText("{this} deals damage equal to the number of lands you control to target creature")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(LandsYouControlHint.instance); + + // * Destroy target land creature or nonbasic land. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetPermanent(filter))); + } + + private BumiBash(final BumiBash card) { + super(card); + } + + @Override + public BumiBash copy() { + return new BumiBash(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java b/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java new file mode 100644 index 00000000000..66ac62d7a24 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BumiKingOfThreeTrials.java @@ -0,0 +1,88 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.effects.keyword.ScryTargetEffect; +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.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BumiKingOfThreeTrials extends CardImpl { + + public BumiKingOfThreeTrials(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Bumi enters, choose up to X, where X is the number of Lesson cards in your graveyard -- + // * Put three +1/+1 counters on Bumi. + // * Target player scries 3. + // * Earthbend 3. + this.addAbility(new BumiKingOfThreeTrialsTriggeredAbility()); + } + + private BumiKingOfThreeTrials(final BumiKingOfThreeTrials card) { + super(card); + } + + @Override + public BumiKingOfThreeTrials copy() { + return new BumiKingOfThreeTrials(this); + } +} + +class BumiKingOfThreeTrialsTriggeredAbility extends EntersBattlefieldTriggeredAbility { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON)); + + BumiKingOfThreeTrialsTriggeredAbility() { + super(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3))); + this.getModes().setChooseText("choose up to X, where X is the number of Lesson cards in your graveyard —"); + this.getModes().setMinModes(0); + this.addMode(new Mode(new ScryTargetEffect(3)).addTarget(new TargetPlayer())); + this.addMode(new Mode(new EarthbendTargetEffect(3)).addTarget(new TargetControlledLandPermanent())); + this.addHint(LessonsInGraveCondition.getHint()); + } + + private BumiKingOfThreeTrialsTriggeredAbility(final BumiKingOfThreeTrialsTriggeredAbility ability) { + super(ability); + } + + @Override + public BumiKingOfThreeTrialsTriggeredAbility copy() { + return new BumiKingOfThreeTrialsTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + this.getModes().setMaxModes(xValue.calculate(game, this, null)); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BumiUnleashed.java b/Mage.Sets/src/mage/cards/b/BumiUnleashed.java new file mode 100644 index 00000000000..06938b8f27d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BumiUnleashed.java @@ -0,0 +1,131 @@ +package mage.cards.b; + +import java.util.UUID; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.UntapAllLandsControllerEffect; +import mage.abilities.effects.common.combat.CantAttackAllEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.constants.*; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.turn.TurnMod; +import mage.target.common.TargetControlledLandPermanent; + +/** + * + * @author Grath + */ +public final class BumiUnleashed extends CardImpl { + + public BumiUnleashed(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Bumi enters, earthbend 4. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(4)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // Whenever Bumi deals combat damage to a player, untap all lands you control. After this phase, there is an additional combat phase. Only land creatures can attack during that combat phase. + ability = new DealsCombatDamageToAPlayerTriggeredAbility(new UntapAllLandsControllerEffect(), false); + ability.addEffect(new BumiUnleashedEffect()); + this.addAbility(ability); + } + + private BumiUnleashed(final BumiUnleashed card) { + super(card); + } + + @Override + public BumiUnleashed copy() { + return new BumiUnleashed(this); + } +} + +//Based on LastNightTogetherEffect +class BumiUnleashedEffect extends OneShotEffect { + + BumiUnleashedEffect() { + super(Outcome.Benefit); + staticText = "After this phase, there is an additional combat phase. Only land creatures can attack during that combat phase"; + } + + private BumiUnleashedEffect(final BumiUnleashedEffect effect) { + super(effect); + } + + @Override + public BumiUnleashedEffect copy() { + return new BumiUnleashedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + // At the start of that combat, add a restriction effect preventing other creatures from attacking. + TurnMod combat = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.COMBAT); + game.getState().getTurnMods().add(combat); + BumiUnleashedDelayedCantAttackAbility delayedTriggeredAbility = new BumiUnleashedDelayedCantAttackAbility(combat.getId()); + game.addDelayedTriggeredAbility(delayedTriggeredAbility, source); + return true; + } + +} + +class BumiUnleashedDelayedCantAttackAbility extends DelayedTriggeredAbility { + + private final UUID connectedTurnMod; + + BumiUnleashedDelayedCantAttackAbility(UUID connectedTurnMod) { + super(null, Duration.EndOfTurn); + FilterCreaturePermanent filterRestriction = new FilterCreaturePermanent(); + filterRestriction.add(Predicates.not(CardType.LAND.getPredicate())); + this.addEffect(new CantAttackAllEffect(Duration.EndOfCombat, filterRestriction)); + this.usesStack = false; // don't show this to the user + this.connectedTurnMod = connectedTurnMod; + } + + BumiUnleashedDelayedCantAttackAbility(BumiUnleashedDelayedCantAttackAbility ability) { + super(ability); + this.connectedTurnMod = ability.connectedTurnMod; + } + + @Override + public BumiUnleashedDelayedCantAttackAbility copy() { + return new BumiUnleashedDelayedCantAttackAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PHASE_CHANGED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return (event.getType() == GameEvent.EventType.PHASE_CHANGED && this.connectedTurnMod.equals(event.getSourceId())); + } + + @Override + public String getRule() { + return "Only land creatures can attack during that combat phase"; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java b/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java new file mode 100644 index 00000000000..ef951b36622 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BumisFeastLecture.java @@ -0,0 +1,51 @@ +package mage.cards.b; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BumisFeastLecture extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterControlledPermanent(SubType.FOOD, "twice the number of Foods you control"), 2 + ); + private static final Hint hint = new ValueHint( + "Foods you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.FOOD)) + ); + + public BumisFeastLecture(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + this.subtype.add(SubType.LESSON); + + // Create a Food token. Then earthbend X, where X is twice the number of Foods you control. + this.getSpellAbility().addEffect(new CreateTokenEffect(new FoodToken())); + this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue, true).concatBy("Then")); + this.getSpellAbility().addTarget(new TargetControlledLandPermanent()); + this.getSpellAbility().addHint(hint); + } + + private BumisFeastLecture(final BumisFeastLecture card) { + super(card); + } + + @Override + public BumisFeastLecture copy() { + return new BumisFeastLecture(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BurlyBreaker.java b/Mage.Sets/src/mage/cards/b/BurlyBreaker.java index da7065a2329..d4d3f353148 100644 --- a/Mage.Sets/src/mage/cards/b/BurlyBreaker.java +++ b/Mage.Sets/src/mage/cards/b/BurlyBreaker.java @@ -1,11 +1,11 @@ package mage.cards.b; -import mage.MageInt; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,22 +14,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class BurlyBreaker extends CardImpl { +public final class BurlyBreaker extends TransformingDoubleFacedCard { public BurlyBreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{G}{G}", + "Dire-Strain Demolisher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.d.DireStrainDemolisher.class; + // Burly Breaker + this.getLeftHalfCard().setPT(6, 5); // Ward {1} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Dire-Strain Demolisher + this.getRightHalfCard().setPT(8, 7); + + // Ward {3} + this.getRightHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{3}"))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private BurlyBreaker(final BurlyBreaker card) { diff --git a/Mage.Sets/src/mage/cards/b/BurningEarth.java b/Mage.Sets/src/mage/cards/b/BurningEarth.java index 36d30a2a340..7449ebdfc43 100644 --- a/Mage.Sets/src/mage/cards/b/BurningEarth.java +++ b/Mage.Sets/src/mage/cards/b/BurningEarth.java @@ -29,7 +29,7 @@ public final class BurningEarth extends CardImpl { // Whenever a player taps a nonbasic land for mana, Burning Earth deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), filter, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/b/BurningSunsAvatar.java b/Mage.Sets/src/mage/cards/b/BurningSunsAvatar.java index 0aca1c22fc8..4394b57717d 100644 --- a/Mage.Sets/src/mage/cards/b/BurningSunsAvatar.java +++ b/Mage.Sets/src/mage/cards/b/BurningSunsAvatar.java @@ -1,12 +1,9 @@ - package mage.cards.b; -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.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,6 +11,8 @@ import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** * * @author TheElk801 @@ -29,11 +28,9 @@ public final class BurningSunsAvatar extends CardImpl { this.toughness = new MageInt(6); // When Burning Sun's Avatar enters the battlefield, it deals 3 damage to target opponent and 3 damage to up to one target creature. - Effect effect = new DamageTargetEffect(3); - effect.setText("it deals 3 damage to target opponent or planeswalker and 3 damage to up to one target creature"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetOpponentOrPlaneswalker()); - ability.addTarget(new TargetCreaturePermanent(0, 1)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetAndTargetEffect(3, 3)); + ability.addTarget(new TargetOpponentOrPlaneswalker().setTargetTag(1)); + ability.addTarget(new TargetCreaturePermanent(0, 1).setTargetTag(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java index 4b0fd3eac54..aa615d6b308 100644 --- a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java +++ b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java @@ -2,7 +2,6 @@ package mage.cards.b; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -46,7 +45,8 @@ public final class BurningTreeShaman extends CardImpl { class BurningTreeShamanTriggeredAbility extends TriggeredAbilityImpl { BurningTreeShamanTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); + setTriggerPhrase("Whenever a player activates an ability that isn't a mana ability, "); } private BurningTreeShamanTriggeredAbility(final BurningTreeShamanTriggeredAbility ability) { @@ -75,8 +75,4 @@ class BurningTreeShamanTriggeredAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever a player activates an ability that isn't a mana ability, {this} deals 1 damage to that player."; - } } diff --git a/Mage.Sets/src/mage/cards/b/BurnishedDunestomper.java b/Mage.Sets/src/mage/cards/b/BurnishedDunestomper.java deleted file mode 100644 index ad484ef7305..00000000000 --- a/Mage.Sets/src/mage/cards/b/BurnishedDunestomper.java +++ /dev/null @@ -1,41 +0,0 @@ -package mage.cards.b; - -import mage.MageInt; -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 BurnishedDunestomper extends CardImpl { - - public BurnishedDunestomper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.DOG); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - } - - private BurnishedDunestomper(final BurnishedDunestomper card) { - super(card); - } - - @Override - public BurnishedDunestomper copy() { - return new BurnishedDunestomper(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CacklingCulprit.java b/Mage.Sets/src/mage/cards/c/CacklingCulprit.java deleted file mode 100644 index c3cbc192ecf..00000000000 --- a/Mage.Sets/src/mage/cards/c/CacklingCulprit.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.GainLifeEffect; -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 mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CacklingCulprit extends CardImpl { - - public CacklingCulprit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever Cackling Culprit or another creature you control dies, you gain 1 life. - this.addAbility(new DiesThisOrAnotherTriggeredAbility( - new GainLifeEffect(1), false, StaticFilters.FILTER_CONTROLLED_CREATURE - )); - - // {1}{B}: Cackling Culprit gains deathtouch until end of turn. - this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( - DeathtouchAbility.getInstance(), Duration.EndOfTurn - ), new ManaCostsImpl<>("{1}{B}"))); - } - - private CacklingCulprit(final CacklingCulprit card) { - super(card); - } - - @Override - public CacklingCulprit copy() { - return new CacklingCulprit(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CaetusSeaTyrantOfSegovia.java b/Mage.Sets/src/mage/cards/c/CaetusSeaTyrantOfSegovia.java deleted file mode 100644 index be5fd3a7870..00000000000 --- a/Mage.Sets/src/mage/cards/c/CaetusSeaTyrantOfSegovia.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; -import mage.abilities.keyword.ConvokeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.common.FilterNonlandCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CaetusSeaTyrantOfSegovia extends CardImpl { - - private static final FilterNonlandCard filter = new FilterNonlandCard("noncreature spells you cast"); - - static { - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - filter.add(Predicates.not(new AbilityPredicate(ConvokeAbility.class))); // So there are not redundant copies being added to each card - } - - public CaetusSeaTyrantOfSegovia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SERPENT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.nightCard = true; - - // Noncreature spells you cast have convoke. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); - - // At the beginning of your end step, untap up to four target creatures. - Ability ability = new BeginningOfEndStepTriggeredAbility( - new UntapTargetEffect() - ); - ability.addTarget(new TargetCreaturePermanent(0, 4)); - this.addAbility(ability); - } - - private CaetusSeaTyrantOfSegovia(final CaetusSeaTyrantOfSegovia card) { - super(card); - } - - @Override - public CaetusSeaTyrantOfSegovia copy() { - return new CaetusSeaTyrantOfSegovia(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CallousGiant.java b/Mage.Sets/src/mage/cards/c/CallousGiant.java index ae5bad00412..1cc430a5560 100644 --- a/Mage.Sets/src/mage/cards/c/CallousGiant.java +++ b/Mage.Sets/src/mage/cards/c/CallousGiant.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,12 +8,13 @@ import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.game.Game; import mage.game.events.GameEvent; +import java.util.UUID; + /** * * @author LoneFox @@ -63,7 +63,6 @@ class CallousGiantEffect extends PreventionEffectImpl { if(event.getAmount() <= 3) { preventDamageAction(event, source, game); - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CallousInspector.java b/Mage.Sets/src/mage/cards/c/CallousInspector.java new file mode 100644 index 00000000000..0f092d36217 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CallousInspector.java @@ -0,0 +1,47 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CallousInspector extends CardImpl { + + public CallousInspector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature dies, it deals 1 damage to you. Create a Clue token. + Ability ability = new DiesSourceTriggeredAbility(new DamageControllerEffect(1, "it")); + ability.addEffect(new CreateTokenEffect(new ClueArtifactToken())); + this.addAbility(ability); + } + + private CallousInspector(final CallousInspector card) { + super(card); + } + + @Override + public CallousInspector copy() { + return new CallousInspector(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CandlesGlow.java b/Mage.Sets/src/mage/cards/c/CandlesGlow.java index 789c20daff0..0a33180260d 100644 --- a/Mage.Sets/src/mage/cards/c/CandlesGlow.java +++ b/Mage.Sets/src/mage/cards/c/CandlesGlow.java @@ -1,6 +1,7 @@ package mage.cards.c; import mage.abilities.Ability; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.keyword.SpliceAbility; import mage.cards.CardImpl; @@ -9,10 +10,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.players.Player; import mage.target.common.TargetAnyTarget; @@ -50,7 +48,7 @@ class CandlesGlowPreventDamageTargetEffect extends PreventionEffectImpl { private int amount = 3; public CandlesGlowPreventDamageTargetEffect(Duration duration) { - super(duration); + super(duration, 3, false); staticText = "Prevent the next 3 damage that would be dealt to any target this turn. You gain life equal to the damage prevented this way"; } @@ -66,39 +64,17 @@ class CandlesGlowPreventDamageTargetEffect 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; - if (event.getAmount() >= this.amount) { - int damage = amount; - event.setAmount(event.getAmount() - amount); - this.used = true; - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; - } else { - int damage = event.getAmount(); - event.setAmount(0); - amount -= damage; - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; - } - - // add live now - if (prevented > 0) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.gainLife(prevented, game, source); - game.informPlayers("Candles' Glow: Prevented " + prevented + " damage "); - game.informPlayers("Candles' Glow: " + controller.getLogName() + " gained " + prevented + "life"); - } - } + PreventionEffectData preventionData = preventDamageAction(event, source, game); + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(preventionData.getPreventedDamage(), game, source); } return false; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!this.used && super.applies(event, source, game)) { + if (super.applies(event, source, game)) { return source.getTargets().getFirstTarget().equals(event.getTargetId()); } return false; diff --git a/Mage.Sets/src/mage/cards/c/CanyonCrawler.java b/Mage.Sets/src/mage/cards/c/CanyonCrawler.java new file mode 100644 index 00000000000..64bced505f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CanyonCrawler.java @@ -0,0 +1,48 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.SwampcyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CanyonCrawler extends CardImpl { + + public CanyonCrawler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.SPIDER); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When this creature enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // Swampcycling {2} + this.addAbility(new SwampcyclingAbility(new ManaCostsImpl<>("{2}"))); + } + + private CanyonCrawler(final CanyonCrawler card) { + super(card); + } + + @Override + public CanyonCrawler copy() { + return new CanyonCrawler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CaptainAmericaSuperSoldier.java b/Mage.Sets/src/mage/cards/c/CaptainAmericaSuperSoldier.java new file mode 100644 index 00000000000..5f172a134a7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaptainAmericaSuperSoldier.java @@ -0,0 +1,72 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +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.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CaptainAmericaSuperSoldier extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.SHIELD); + private static final FilterPermanent filter = new FilterPermanent(SubType.HERO, "Heroes"); + + public CaptainAmericaSuperSoldier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Captain America enters with a shield counter on him. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance()), + "with a shield counter on him" + )); + + // As long as Captain America has a shield counter on him, you and other Heroes you control have hexproof. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityControllerEffect(HexproofAbility.getInstance()), + condition, "as long as {this} has a shield counter on him, you" + )); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ), condition, null).concatBy("and")); + this.addAbility(ability); + } + + private CaptainAmericaSuperSoldier(final CaptainAmericaSuperSoldier card) { + super(card); + } + + @Override + public CaptainAmericaSuperSoldier copy() { + return new CaptainAmericaSuperSoldier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CaptiveWeird.java b/Mage.Sets/src/mage/cards/c/CaptiveWeird.java index 80fd4e22171..c1bcfa2fb5c 100644 --- a/Mage.Sets/src/mage/cards/c/CaptiveWeird.java +++ b/Mage.Sets/src/mage/cards/c/CaptiveWeird.java @@ -1,14 +1,15 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import java.util.UUID; @@ -16,22 +17,33 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CaptiveWeird extends CardImpl { +public final class CaptiveWeird extends TransformingDoubleFacedCard { public CaptiveWeird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEIRD}, "{U}", + "Compleated Conjurer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.WEIRD}, "UR"); - this.subtype.add(SubType.WEIRD); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.c.CompleatedConjurer.class; + // Captive Weird + this.getLeftHalfCard().setPT(1, 3); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {3}{R/P}: Transform Captive Weird. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R/P}") + )); + + // Compleated Conjurer + this.getRightHalfCard().setPT(3, 3); + + // When this creature transforms into Compleated Conjurer, exile the top card of your library. + // Until the end of your next turn, you may play that card. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility( + new ExileTopXMayPlayUntilEffect(1, Duration.UntilEndOfYourNextTurn) + )); } private CaptiveWeird(final CaptiveWeird card) { diff --git a/Mage.Sets/src/mage/cards/c/CarnageCrimsonChaos.java b/Mage.Sets/src/mage/cards/c/CarnageCrimsonChaos.java index 12860badb5b..44520925e69 100644 --- a/Mage.Sets/src/mage/cards/c/CarnageCrimsonChaos.java +++ b/Mage.Sets/src/mage/cards/c/CarnageCrimsonChaos.java @@ -16,6 +16,7 @@ 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; @@ -32,7 +33,7 @@ import java.util.UUID; */ public final class CarnageCrimsonChaos extends CardImpl { - private static final FilterCard filter = new FilterCard("creature card with mana value 3 or less"); + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 3 or less"); static { filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); diff --git a/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java index 8ff9875068c..33452f3972e 100644 --- a/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java +++ b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java @@ -1,6 +1,6 @@ package mage.cards.c; -import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardSetInfo; @@ -22,8 +22,7 @@ public final class CarnivalCarnage extends SplitCard { // Carnival // Carnival deals 1 damage to target creature or planeswalker and 1 damage to that permanent's controller. - this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(1)); - this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetControllerEffect(1).setText("and 1 damage to that permanent's controller")); + this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetAndTargetControllerEffect(1, 1)); this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); // Carnage diff --git a/Mage.Sets/src/mage/cards/c/CasalLurkwoodPathfinder.java b/Mage.Sets/src/mage/cards/c/CasalLurkwoodPathfinder.java index 27e9538d02f..87a3d7580c7 100644 --- a/Mage.Sets/src/mage/cards/c/CasalLurkwoodPathfinder.java +++ b/Mage.Sets/src/mage/cards/c/CasalLurkwoodPathfinder.java @@ -1,19 +1,25 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterLandCard; import mage.target.common.TargetCardInLibrary; @@ -22,37 +28,59 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CasalLurkwoodPathfinder extends CardImpl { +public final class CasalLurkwoodPathfinder extends TransformingDoubleFacedCard { private static final FilterLandCard filter = new FilterLandCard("Forest card"); + private static final FilterCreaturePermanent filterLegendary = new FilterCreaturePermanent(); static { filter.add(SubType.FOREST.getPredicate()); + filterLegendary.add(SuperType.LEGENDARY.getPredicate()); } public CasalLurkwoodPathfinder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TIEFLING, SubType.DRUID}, "{3}{G}", + "Casal, Pathbreaker Owlbear", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BIRD, SubType.BEAR}, "G" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.TIEFLING); - this.subtype.add(SubType.DRUID); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = CasalPathbreakerOwlbear.class; + // Casal, Lurkwood Pathfinder + this.getLeftHalfCard().setPT(3, 3); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); - // When Doric, Nature's Warden enters the battlefield, search your library for a Forest card, put it into the battlefield tapped, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility( + // When Casal, Lurkwood Pathfinder enters the battlefield, search your library for a Forest card, put it into the battlefield tapped, then shuffle. + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) )); - // Whenever Doric attacks, you may pay {1}{G}. If you do, transform her. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + // Whenever Casal attacks, you may pay {1}{G}. If you do, transform her. + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( new TransformSourceEffect().setText("transform her"), new ManaCostsImpl<>("{1}{G}") ))); + + // Casal, Pathbreaker Owlbear + this.getRightHalfCard().setPT(6, 6); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // When this creature transforms into Casal, Pathbreaker Owlbear, other legendary creatures you control get +2/+2 and gain trample until end of turn. + Ability ability = new TransformIntoSourceTriggeredAbility(new BoostControlledEffect( + 2, 2, Duration.EndOfTurn, filterLegendary, true + ).setText("other legendary creatures you control get +2/+2")); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, filterLegendary, true + ).setText("and gain trample until end of turn")); + this.getRightHalfCard().addAbility(ability); + + // At the beginning of your upkeep, transform Casal. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect())); } private CasalLurkwoodPathfinder(final CasalLurkwoodPathfinder card) { diff --git a/Mage.Sets/src/mage/cards/c/CasalPathbreakerOwlbear.java b/Mage.Sets/src/mage/cards/c/CasalPathbreakerOwlbear.java deleted file mode 100644 index 6d62625d256..00000000000 --- a/Mage.Sets/src/mage/cards/c/CasalPathbreakerOwlbear.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CasalPathbreakerOwlbear extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - public CasalPathbreakerOwlbear(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.BIRD); - this.subtype.add(SubType.BEAR); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setGreen(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // When this creature transforms into Doric, Owlbear Avenger, other legendary creatures you control get +2/+2 and gain trample until end of turn. - Ability ability = new TransformIntoSourceTriggeredAbility(new BoostControlledEffect( - 2, 2, Duration.EndOfTurn, filter, true - ).setText("other legendary creatures you control get +2/+2")); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, filter, true - ).setText("and gain trample until end of turn")); - this.addAbility(ability); - - // At the beginning of your upkeep, transform Doric. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect())); - } - - private CasalPathbreakerOwlbear(final CasalPathbreakerOwlbear card) { - super(card); - } - - @Override - public CasalPathbreakerOwlbear copy() { - return new CasalPathbreakerOwlbear(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CaseyJonesJuryRigJusticiar.java b/Mage.Sets/src/mage/cards/c/CaseyJonesJuryRigJusticiar.java new file mode 100644 index 00000000000..1235b108809 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaseyJonesJuryRigJusticiar.java @@ -0,0 +1,48 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CaseyJonesJuryRigJusticiar extends CardImpl { + + public CaseyJonesJuryRigJusticiar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When Casey Jones enters, 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 a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_RANDOM + ))); + } + + private CaseyJonesJuryRigJusticiar(final CaseyJonesJuryRigJusticiar card) { + super(card); + } + + @Override + public CaseyJonesJuryRigJusticiar copy() { + return new CaseyJonesJuryRigJusticiar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CatapultCaptain.java b/Mage.Sets/src/mage/cards/c/CatapultCaptain.java deleted file mode 100644 index 59660863339..00000000000 --- a/Mage.Sets/src/mage/cards/c/CatapultCaptain.java +++ /dev/null @@ -1,53 +0,0 @@ -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.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.StaticFilters; -import mage.target.common.TargetOpponent; - -/** - * - * @author weirddan455 - */ -public final class CatapultCaptain extends CardImpl { - - public CatapultCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ZOMBIE); - this.color.setBlack(true); - this.power = new MageInt(2); - this.toughness = new MageInt(6); - - // Back half of Catapult Fodder - this.nightCard = true; - - // {2}{B}, {T}, Sacrifice another creature: Target opponent loses life equal to the sacrificed creature's toughness. - Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(SacrificeCostCreaturesToughness.instance) - .setText("Target opponent loses life equal to the sacrificed creature's toughness"), new ManaCostsImpl<>("{2}{B}")); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private CatapultCaptain(final CatapultCaptain card) { - super(card); - } - - @Override - public CatapultCaptain copy() { - return new CatapultCaptain(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CatapultFodder.java b/Mage.Sets/src/mage/cards/c/CatapultFodder.java index 97882939d50..99cba995c07 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultFodder.java +++ b/Mage.Sets/src/mage/cards/c/CatapultFodder.java @@ -1,29 +1,36 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ToughnessGreaterThanPowerPredicate; +import mage.target.common.TargetOpponent; import java.util.UUID; /** * @author weirddan455 */ -public final class CatapultFodder extends CardImpl { +public final class CatapultFodder extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledCreaturePermanent( "you control three or more creatures that each have toughness greater than their power" @@ -39,16 +46,27 @@ public final class CatapultFodder extends CardImpl { ); public CatapultFodder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "{2}{B}", + "Catapult Captain", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "B"); - this.subtype.add(SubType.ZOMBIE); - this.power = new MageInt(1); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.c.CatapultCaptain.class; + // Catapult Fodder + this.getLeftHalfCard().setPT(1, 5); // At the beginning of combat on your turn, if you control three or more creatures that each have toughness greater than their power, transform Catapult Fodder. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + this.getLeftHalfCard().addAbility(new BeginningOfCombatTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + + // Catapult Captain + this.getRightHalfCard().setPT(2, 6); + + // {2}{B}, {T}, Sacrifice another creature: Target opponent loses life equal to the sacrificed creature's toughness. + Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(SacrificeCostCreaturesToughness.instance) + .setText("Target opponent loses life equal to the sacrificed creature's toughness"), new ManaCostsImpl<>("{2}{B}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + ability.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(ability); } private CatapultFodder(final CatapultFodder card) { diff --git a/Mage.Sets/src/mage/cards/c/CatlikeCuriosity.java b/Mage.Sets/src/mage/cards/c/CatlikeCuriosity.java deleted file mode 100644 index c741013939f..00000000000 --- a/Mage.Sets/src/mage/cards/c/CatlikeCuriosity.java +++ /dev/null @@ -1,58 +0,0 @@ -package mage.cards.c; - -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -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.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CatlikeCuriosity extends CardImpl { - - public CatlikeCuriosity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has "Whenever this creature deals combat damage to a player, draw a card." - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( - new DealsCombatDamageToAPlayerTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - ).setTriggerPhrase("Whenever this creature deals combat damage to a player, "), AttachmentType.AURA - ))); - - // If Catlike Curiosity would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private CatlikeCuriosity(final CatlikeCuriosity card) { - super(card); - } - - @Override - public CatlikeCuriosity copy() { - return new CatlikeCuriosity(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java b/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java index f04cf84aa28..b7bc80602c7 100644 --- a/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java +++ b/Mage.Sets/src/mage/cards/c/CecilDarkKnight.java @@ -1,7 +1,7 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DealsDamageSourceTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -9,13 +9,17 @@ import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.game.Controllable; import mage.game.Game; import mage.players.Player; @@ -26,24 +30,21 @@ import java.util.UUID; /** * @author balazskristof */ -public final class CecilDarkKnight extends CardImpl { +public final class CecilDarkKnight extends TransformingDoubleFacedCard { public CecilDarkKnight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "{B}", + "Cecil, Redeemed Paladin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "W"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.c.CecilRedeemedPaladin.class; + // Cecil, Dark Knight + this.getLeftHalfCard().setPT(2, 3); // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); + this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance()); // Darkness -- Whenever Cecil deals damage, you lose that much life. Then if your life total is less than or equal to half your starting life total, untap Cecil and transform it. - this.addAbility(new TransformAbility()); Ability ability = new DealsDamageSourceTriggeredAbility(new LoseLifeSourceControllerEffect(SavedDamageValue.MUCH), false).withFlavorWord("Darkness"); ability.addEffect(new ConditionalOneShotEffect( new UntapSourceEffect(), @@ -51,7 +52,19 @@ public final class CecilDarkKnight extends CardImpl { ).addEffect( new TransformSourceEffect(true).concatBy("and") ).concatBy("Then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Cecil, Redeemed Paladin + this.getRightHalfCard().setPT(4, 4); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Protect -- Whenever Cecil attacks, other attacking creatures gain indestructible until end of turn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_ATTACKING_CREATURES, true + )).withFlavorWord("Protect")); } private CecilDarkKnight(final CecilDarkKnight card) { diff --git a/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java b/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java deleted file mode 100644 index 2e6f4f4999c..00000000000 --- a/Mage.Sets/src/mage/cards/c/CecilRedeemedPaladin.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.c; - -import java.util.UUID; -import mage.MageInt; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; - -/** - * @author balazskristof - */ -public final class CecilRedeemedPaladin extends CardImpl { - - public CecilRedeemedPaladin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.color.setWhite(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Protect -- Whenever Cecil attacks, other attacking creatures gain indestructible until end of turn. - this.addAbility(new AttacksTriggeredAbility(new GainAbilityAllEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_ATTACKING_CREATURES, true - )).withFlavorWord("Protect")); - } - - private CecilRedeemedPaladin(final CecilRedeemedPaladin card) { - super(card); - } - - @Override - public CecilRedeemedPaladin copy() { - return new CecilRedeemedPaladin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java index 9ec04a37b8b..54fd2fb2943 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java @@ -99,7 +99,7 @@ class CemeteryGatekeeperEffect extends OneShotEffect { class CemeteryGatekeeperTriggeredAbility extends TriggeredAbilityImpl { public CemeteryGatekeeperTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); setTriggerPhrase("Whenever a player plays a land or casts a spell, if it shares a card type with the exiled card, "); } diff --git a/Mage.Sets/src/mage/cards/c/ChakraMeditation.java b/Mage.Sets/src/mage/cards/c/ChakraMeditation.java new file mode 100644 index 00000000000..e6aaca2b37d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChakraMeditation.java @@ -0,0 +1,52 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +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 ChakraMeditation extends CardImpl { + + public ChakraMeditation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // When this enchantment enters, return up to one target instant or sorcery card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // Whenever you cast an instant or sorcery spell, draw a card. Then discard a card unless there are three or more Lesson cards in your graveyard. + ability = new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + ); + ability.addEffect(new ConditionalOneShotEffect( + null, new DiscardControllerEffect(1), LessonsInGraveCondition.THREE, + "Then discard a card unless there are three or more Lesson cards in your graveyard" + )); + this.addAbility(ability.addHint(LessonsInGraveCondition.getHint())); + } + + private ChakraMeditation(final ChakraMeditation card) { + super(card); + } + + @Override + public ChakraMeditation copy() { + return new ChakraMeditation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java b/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java deleted file mode 100644 index 7a3263e9c24..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfDeath.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.c; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.target.TargetPlayer; - -/** - * - * @author intimidatingant - */ -public final class ChaliceOfDeath extends CardImpl { - - public ChaliceOfDeath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},""); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {tap}: Target player loses 5 life. - Ability ability = new SimpleActivatedAbility(new LoseLifeTargetEffect(5), new TapSourceCost()); - ability.addTarget(new TargetPlayer()); - this.addAbility(ability); - } - - private ChaliceOfDeath(final ChaliceOfDeath card) { - super(card); - } - - @Override - public ChaliceOfDeath copy() { - return new ChaliceOfDeath(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java index f809074e503..4a0606729fe 100644 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java +++ b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java @@ -6,32 +6,41 @@ import mage.abilities.condition.common.MoreThanStartingLifeTotalCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; import java.util.UUID; /** * @author intimidatingant */ -public final class ChaliceOfLife extends CardImpl { +public final class ChaliceOfLife extends TransformingDoubleFacedCard { public ChaliceOfLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Chalice of Death", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, ""); - this.secondSideCardClazz = mage.cards.c.ChaliceOfDeath.class; - this.addAbility(new TransformAbility()); - - // {tap}: You gain 1 life. Then if you have at least 10 life more than your starting life total, transform Chalice of Life. + // Chalice of Life + // {T}: You gain 1 life. Then if you have at least 10 life more than your starting life total, transform Chalice of Life. Ability ability = new SimpleActivatedAbility(new GainLifeEffect(1), new TapSourceCost()); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), MoreThanStartingLifeTotalCondition.TEN, "Then if you have at least 10 life more than your starting life total, transform {this}" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Chalice of Death + // {T}: Target player loses 5 life. + Ability deathAbility = new SimpleActivatedAbility(new LoseLifeTargetEffect(5), new TapSourceCost()); + deathAbility.addTarget(new TargetPlayer()); + this.getRightHalfCard().addAbility(deathAbility); } private ChaliceOfLife(final ChaliceOfLife card) { diff --git a/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java b/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java index cbe8871a1aa..2e98d2cdca8 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFireOfKaladesh.java @@ -1,63 +1,79 @@ - package mage.cards.c; -import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceDealtDamageCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.command.emblems.ChandraRoaringFlameEmblem; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import mage.watchers.common.DamageDoneWatcher; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; /** * @author LevelX2 */ -public final class ChandraFireOfKaladesh extends CardImpl { +public final class ChandraFireOfKaladesh extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("a red spell"); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - } - + static { filter.add(new ColorPredicate(ObjectColor.RED)); } private static final Condition condition = new SourceDealtDamageCondition(3); public ChandraFireOfKaladesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "{1}{R}{R}", + "Chandra, Roaring Flame", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.CHANDRA}, "R"); - this.secondSideCardClazz = mage.cards.c.ChandraRoaringFlame.class; + // Chandra, Fire of Kaladesh + this.getLeftHalfCard().setPT(2, 2); // Whenever you cast a red spell, untap Chandra, Fire of Kaladesh. - this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); - // {T}: Chandra, Fire of Kaladesh deals 1 damage to target player. If Chandra has dealt 3 or more damage this turn, exile her, then return her to the battlefield transformed under her owner's control. - this.addAbility(new TransformAbility()); + // {T}: Chandra, Fire of Kaladesh deals 1 damage to target player or planeswalker. If Chandra has dealt 3 or more damage this turn, exile her, then return her to the battlefield transformed under her owner's control. Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); ability.addEffect(new ConditionalOneShotEffect( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE), condition )); ability.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(ability, new DamageDoneWatcher()); + ability.addWatcher(new DamageDoneWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Chandra, Roaring Flame + this.getRightHalfCard().setStartingLoyalty(4); + + // +1: Chandra, Roaring Flame deals 2 damage to target player or planeswalker. + LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); + loyaltyAbility.addTarget(new TargetPlayerOrPlaneswalker()); + this.getRightHalfCard().addAbility(loyaltyAbility); + + // -2: Chandra, Roaring Flame deals 2 damage to target creature. + loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), -2); + loyaltyAbility.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(loyaltyAbility); + + // -7: Chandra, Roaring Flame deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." + this.getRightHalfCard().addAbility(new LoyaltyAbility(new ChandraRoaringFlameEmblemEffect(), -7)); } private ChandraFireOfKaladesh(final ChandraFireOfKaladesh card) { @@ -69,3 +85,31 @@ public final class ChandraFireOfKaladesh extends CardImpl { return new ChandraFireOfKaladesh(this); } } + +class ChandraRoaringFlameEmblemEffect extends OneShotEffect { + + ChandraRoaringFlameEmblemEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with \"At the beginning of your upkeep, this emblem deals 3 damage to you.\""; + } + + private ChandraRoaringFlameEmblemEffect(final ChandraRoaringFlameEmblemEffect effect) { super(effect); } + @Override public ChandraRoaringFlameEmblemEffect copy() { return new ChandraRoaringFlameEmblemEffect(this); } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + List opponentsEmblem = new ArrayList<>(); + for (UUID playerId : game.getOpponents(controller.getId())) { + Player opponent = game.getPlayer(playerId); + if (opponent != null && opponent.damage(6, source, game) > 0) { + opponentsEmblem.add(opponent); + } + } + for (Player opponent : opponentsEmblem) { + game.addEmblem(new ChandraRoaringFlameEmblem(), source.getSourceObject(game), opponent.getId()); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java b/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java index a3303380cae..16beae1a99b 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java @@ -2,19 +2,14 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageAllControlledTargetEffect; +import mage.abilities.effects.common.DamageTargetAndAllControlledEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; 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.constants.SuperType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; @@ -39,15 +34,12 @@ public final class ChandraFlamesFury extends CardImpl { this.addAbility(ability); // −2: Chandra, Flame's Fury deals 4 damage to target creature and 2 damage to that creature's controller. - ability = new LoyaltyAbility(new ChandraFlamesFuryEffect(), -2); + ability = new LoyaltyAbility(new DamageTargetAndTargetControllerEffect(4, 2), -2); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // −8: Chandra, Flame's Fury deals 10 damage to target player and each creature that player controls. - ability = new LoyaltyAbility(new DamageTargetEffect(10), -8); - ability.addEffect(new DamageAllControlledTargetEffect( - 10, StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("and each creature that player controls")); + ability = new LoyaltyAbility(new DamageTargetAndAllControlledEffect(10), -8); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -61,35 +53,3 @@ public final class ChandraFlamesFury extends CardImpl { return new ChandraFlamesFury(this); } } - -class ChandraFlamesFuryEffect extends OneShotEffect { - - ChandraFlamesFuryEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 4 damage to target creature and 2 damage to that creature's controller."; - } - - private ChandraFlamesFuryEffect(final ChandraFlamesFuryEffect effect) { - super(effect); - } - - @Override - public ChandraFlamesFuryEffect copy() { - return new ChandraFlamesFuryEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - return false; - } - Player player = game.getPlayer(permanent.getControllerId()); - if (player == null) { - return false; - } - permanent.damage(4, source.getSourceId(), source, game); - player.damage(2, source.getSourceId(), source, game); - return true; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java b/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java index 1fb0d5e1482..ec1368360ce 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java +++ b/Mage.Sets/src/mage/cards/c/ChandraHopesBeacon.java @@ -51,9 +51,8 @@ public class ChandraHopesBeacon extends CardImpl { this.addAbility(new LoyaltyAbility(new ChandraHopesBeaconEffect(), 1), new ChandraHopesBeaconWatcher()); //−X: Chandra, Hope’s Beacon deals X damage to each of up to two targets. - LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect( - GetXValue.instance, true, "each of up to two targets" - )); + LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(GetXValue.instance) + .withTargetDescription("each of up to two targets")); loyaltyAbility.addTarget(new TargetAnyTarget(0, 2)); this.addAbility(loyaltyAbility); } diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java index 035f31d6a6d..8a8b4880a1b 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java @@ -36,8 +36,7 @@ public final class ChandraPyromaster extends CardImpl { 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. + // +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. LoyaltyAbility ability1 = new LoyaltyAbility(new ChandraPyromasterEffect1(), 1); Target target1 = new TargetPlayerOrPlaneswalker(); ability1.addTarget(target1); @@ -68,7 +67,7 @@ public final class ChandraPyromaster extends CardImpl { class ChandraPyromasterEffect1 extends OneShotEffect { - public ChandraPyromasterEffect1() { + ChandraPyromasterEffect1() { super(Outcome.Damage); staticText = "{this} deals 1 damage to target player or planeswalker " + "and 1 damage to up to one target creature that player or that " @@ -101,7 +100,7 @@ class ChandraPyromasterEffect1 extends OneShotEffect { class ChandraPyromasterTarget extends TargetPermanent { - public ChandraPyromasterTarget() { + ChandraPyromasterTarget() { super(0, 1, new FilterCreaturePermanent("creature that the targeted player " + "or planeswalker's controller controls"), false); } @@ -138,7 +137,7 @@ class ChandraPyromasterTarget extends TargetPermanent { class ChandraPyromasterEffect2 extends OneShotEffect { - public ChandraPyromasterEffect2() { + ChandraPyromasterEffect2() { super(Outcome.Detriment); this.staticText = "Exile the top card of your library. You may play it this turn"; } diff --git a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java b/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java deleted file mode 100644 index 9759367aa57..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.c; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -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.constants.SuperType; -import mage.game.Game; -import mage.game.command.emblems.ChandraRoaringFlameEmblem; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetPlayerOrPlaneswalker; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class ChandraRoaringFlame extends CardImpl { - - public ChandraRoaringFlame(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CHANDRA); - this.color.setRed(true); - - this.nightCard = true; - - this.setStartingLoyalty(4); - - // +1: Chandra, Roaring Flame deals 2 damage to target player. - LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); - loyaltyAbility.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(loyaltyAbility); - - //-2: Chandra, Roaring Flame deals 2 damage to target creature. - loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), -2); - loyaltyAbility.addTarget(new TargetCreaturePermanent()); - this.addAbility(loyaltyAbility); - - //-7: Chandra, Roaring Flame deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." - this.addAbility(new LoyaltyAbility(new ChandraRoaringFlameEmblemEffect(), -7)); - } - - private ChandraRoaringFlame(final ChandraRoaringFlame card) { - super(card); - } - - @Override - public ChandraRoaringFlame copy() { - return new ChandraRoaringFlame(this); - } -} - -class ChandraRoaringFlameEmblemEffect extends OneShotEffect { - - ChandraRoaringFlameEmblemEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with \"At the beginning of your upkeep, this emblem deals 3 damage to you.\""; - } - - private ChandraRoaringFlameEmblemEffect(final ChandraRoaringFlameEmblemEffect effect) { - super(effect); - } - - @Override - public ChandraRoaringFlameEmblemEffect copy() { - return new ChandraRoaringFlameEmblemEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - List opponentsEmblem = new ArrayList<>(); - for (UUID playerId : game.getOpponents(controller.getId())) { - Player opponent = game.getPlayer(playerId); - if (opponent != null && opponent.damage(6, source, game) > 0) { - opponentsEmblem.add(opponent); - } - } - for (Player opponent : opponentsEmblem) { - game.addEmblem(new ChandraRoaringFlameEmblem(), source.getSourceObject(game), opponent.getId()); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java index 1b145814642..96293d1cc59 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java @@ -36,7 +36,7 @@ public final class ChandraTheFirebrand extends CardImpl { )); // -6: Chandra, the Firebrand deals 6 damage to each of up to six target creatures and/or players - LoyaltyAbility ability2 = new LoyaltyAbility(new DamageTargetEffect(6, true, "each of up to six targets"), -6); + LoyaltyAbility ability2 = new LoyaltyAbility(new DamageTargetEffect(6).withTargetDescription("each of up to six targets"), -6); ability2.addTarget(new TargetAnyTarget(0, 6)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasFury.java b/Mage.Sets/src/mage/cards/c/ChandrasFury.java index 98e752ca138..87f167a107f 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasFury.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasFury.java @@ -1,14 +1,14 @@ - package mage.cards.c; -import java.util.UUID; -import mage.abilities.effects.common.DamageAllControlledTargetEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndAllControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.StaticFilters; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** * * @author North @@ -19,10 +19,8 @@ public final class ChandrasFury extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Chandra's Fury deals 4 damage to target player and 1 damage to each creature that player controls. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addEffect(new DamageAllControlledTargetEffect(1) - .setText("and 1 damage to each creature that player or that planeswalker's controller controls") - ); + this.getSpellAbility().addEffect(new DamageTargetAndAllControlledEffect(4, 1, + StaticFilters.FILTER_PERMANENT_CREATURE)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasOutrage.java b/Mage.Sets/src/mage/cards/c/ChandrasOutrage.java index ddaaed5fe15..e3517234cdf 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasOutrage.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasOutrage.java @@ -1,16 +1,13 @@ - - package mage.cards.c; -import java.util.UUID; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author BetaSteward_at_googlemail.com @@ -21,10 +18,7 @@ public final class ChandrasOutrage extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}"); // Chandra's Outrage deals 4 damage to target creature and 2 damage to that creature's controller. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - Effect effect = new DamageTargetControllerEffect(2); - effect.setText("and 2 damage to that creature's controller"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new DamageTargetAndTargetControllerEffect(4, 2)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/c/ChannelHarm.java b/Mage.Sets/src/mage/cards/c/ChannelHarm.java index 562db66c07d..35755b9db94 100644 --- a/Mage.Sets/src/mage/cards/c/ChannelHarm.java +++ b/Mage.Sets/src/mage/cards/c/ChannelHarm.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.PreventionEffectData; @@ -18,6 +17,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author emerald000 @@ -70,7 +71,7 @@ class ChannelHarmEffect extends PreventionEffectImpl { } } } - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/c/ChaosTheEndless.java b/Mage.Sets/src/mage/cards/c/ChaosTheEndless.java deleted file mode 100644 index cb222c37a81..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChaosTheEndless.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.common.PutOnLibrarySourceEffect; -import mage.abilities.keyword.FlyingAbility; -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 ChaosTheEndless extends CardImpl { - - public ChaosTheEndless(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When Chaos dies, put it on the bottom of its owner's library. - this.addAbility(new DiesSourceTriggeredAbility(new PutOnLibrarySourceEffect( - false, "put it on the bottom of its owner's library" - ), false)); - } - - private ChaosTheEndless(final ChaosTheEndless card) { - super(card); - } - - @Override - public ChaosTheEndless copy() { - return new ChaosTheEndless(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java b/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java deleted file mode 100644 index eb0d21c98ca..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChapelShieldgeist.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FirstStrikeAbility; -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.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ChapelShieldgeist extends CardImpl { - - public ChapelShieldgeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - - // Each creature you control has ward {1}. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("each creature you control has ward {1}. " + - "(Whenever it becomes the target of a spell or ability an opponent controls, " + - "counter it unless that player pays 1.)"))); - - // If Chapel Shieldgeist would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private ChapelShieldgeist(final ChapelShieldgeist card) { - super(card); - } - - @Override - public ChapelShieldgeist copy() { - return new ChapelShieldgeist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java index a6dd19da76b..85ca185e2b4 100644 --- a/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java +++ b/Mage.Sets/src/mage/cards/c/ChaplainOfAlms.java @@ -1,39 +1,63 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 ChaplainOfAlms extends CardImpl { +public final class ChaplainOfAlms extends TransformingDoubleFacedCard { public ChaplainOfAlms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{W}", + "Chapel Shieldgeist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.CLERIC}, "W"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.ChapelShieldgeist.class; + // Chaplain of Alms + this.getLeftHalfCard().setPT(1, 1); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // Ward {1} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); // Disturb {3}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}")); + + // Chapel Shieldgeist + this.getRightHalfCard().setPT(2, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Each creature you control has ward {1}. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("each creature you control has ward {1}. " + + "(Whenever it becomes the target of a spell or ability an opponent controls, counter it unless that player pays 1.)"))); + + // If Chapel Shieldgeist would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private ChaplainOfAlms(final ChaplainOfAlms card) { diff --git a/Mage.Sets/src/mage/cards/c/Char.java b/Mage.Sets/src/mage/cards/c/Char.java index d3fb54b2f59..96fbde8965a 100644 --- a/Mage.Sets/src/mage/cards/c/Char.java +++ b/Mage.Sets/src/mage/cards/c/Char.java @@ -1,15 +1,13 @@ - package mage.cards.c; -import java.util.UUID; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author LevelX2 @@ -19,13 +17,9 @@ public final class Char extends CardImpl { public Char(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); - // Char deals 4 damage to any target and 2 damage to you. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addEffect(new DamageTargetAndYouEffect(4, 2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - Effect effect = new DamageControllerEffect(2); - effect.setText("and 2 damage to you"); - this.getSpellAbility().addEffect(effect); } private Char(final Char card) { diff --git a/Mage.Sets/src/mage/cards/c/ChildOfThePack.java b/Mage.Sets/src/mage/cards/c/ChildOfThePack.java index ca2629315df..c1754ce6e31 100644 --- a/Mage.Sets/src/mage/cards/c/ChildOfThePack.java +++ b/Mage.Sets/src/mage/cards/c/ChildOfThePack.java @@ -1,13 +1,17 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.game.permanent.token.WolfToken; @@ -16,24 +20,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ChildOfThePack extends CardImpl { +public final class ChildOfThePack extends TransformingDoubleFacedCard { public ChildOfThePack(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{G}", + "Savage Packmate", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.s.SavagePackmate.class; + // Child of the Pack + this.getLeftHalfCard().setPT(2, 5); // {2}{R}{G}: Create a 2/2 green Wolf creature token. - this.addAbility(new SimpleActivatedAbility( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( new CreateTokenEffect(new WolfToken()), new ManaCostsImpl<>("{2}{R}{G}") )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Savage Packmate + this.getRightHalfCard().setPT(5, 5); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Other creatures you control get +1/+0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, true + ))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private ChildOfThePack(final ChildOfThePack card) { diff --git a/Mage.Sets/src/mage/cards/c/ChillingChronicle.java b/Mage.Sets/src/mage/cards/c/ChillingChronicle.java deleted file mode 100644 index 12036ef2743..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChillingChronicle.java +++ /dev/null @@ -1,43 +0,0 @@ -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.common.TapTargetEffect; -import mage.abilities.effects.common.TransformSourceEffect; -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 ChillingChronicle extends CardImpl { - - public ChillingChronicle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.color.setBlue(true); - this.nightCard = true; - - // {1}, {T}: Tap target nonland permanent. Transform Chilling Chronicle. - Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); - ability.addCost(new TapSourceCost()); - ability.addEffect(new TransformSourceEffect()); - ability.addTarget(new TargetNonlandPermanent()); - this.addAbility(ability); - } - - private ChillingChronicle(final ChillingChronicle card) { - super(card); - } - - @Override - public ChillingChronicle copy() { - return new ChillingChronicle(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ChocoboCamp.java b/Mage.Sets/src/mage/cards/c/ChocoboCamp.java new file mode 100644 index 00000000000..2c106ed9b3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChocoboCamp.java @@ -0,0 +1,62 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AddCounterNextSpellDelayedTriggeredAbility; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.mana.BasicManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.common.FilterCreatureSpell; +import mage.game.permanent.token.ChocoboToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChocoboCamp extends CardImpl { + + private static final FilterSpell filter = new FilterCreatureSpell("a Bird creature spell"); + + static { + filter.add(SubType.BIRD.getPredicate()); + } + + public ChocoboCamp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a legendary creature. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); + + // {T}: Add {G}. When you next cast a Bird creature spell this turn, it enters with an additional +1/+1 counter on it. + BasicManaAbility manaAbility = new GreenManaAbility(); + manaAbility.addEffect(new CreateDelayedTriggeredAbilityEffect(new AddCounterNextSpellDelayedTriggeredAbility(filter))); + manaAbility.setUndoPossible(false); + this.addAbility(manaAbility); + + // {2}{G}{G}, {T}: Create a 2/2 green Bird creature token with "Whenever a land you control enters, this token gets +1/+0 until end of turn." + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new ChocoboToken()), new ManaCostsImpl<>("{2}{G}{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private ChocoboCamp(final ChocoboCamp card) { + super(card); + } + + @Override + public ChocoboCamp copy() { + return new ChocoboCamp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java b/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java new file mode 100644 index 00000000000..08e51199222 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChongAndLilyNomads.java @@ -0,0 +1,107 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +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.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChongAndLilyNomads extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.BARD, "Bards you control"); + + public ChongAndLilyNomads(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever one or more Bards you control attack, choose one -- + // * Put a lore counter on each of any number of target Sagas you control. + Ability ability = new AttacksWithCreaturesTriggeredAbility( + new AddCountersTargetEffect(CounterType.LORE.createInstance()), 1, filter + ).setTriggerPhrase("Whenever one or more Bards you control attack, "); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, ChongAndLilyNomadsValue.getFilter())); + + // * Creatures you control get +1/+0 until end of turn for each lore counter among Sagas you control. + ability.addMode(new Mode(new BoostControlledEffect( + ChongAndLilyNomadsValue.instance, StaticValue.get(0), Duration.EndOfTurn + ))); + this.addAbility(ability.addHint(ChongAndLilyNomadsValue.getHint())); + } + + private ChongAndLilyNomads(final ChongAndLilyNomads card) { + super(card); + } + + @Override + public ChongAndLilyNomads copy() { + return new ChongAndLilyNomads(this); + } +} + +enum ChongAndLilyNomadsValue implements DynamicValue { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SAGA, "Sagas you control"); + + public static FilterPermanent getFilter() { + return filter; + } + + private static final Hint hint = new ValueHint("Lore counters among Sagas you control", instance); + + public static Hint getHint() { + return hint; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game) + .stream() + .mapToInt(permanent -> permanent.getCounters(game).getCount(CounterType.LORE)) + .sum(); + } + + @Override + public ChongAndLilyNomadsValue copy() { + return this; + } + + @Override + public String getMessage() { + return "lore counter among Sagas you control"; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java index d0d6472ed4e..cd0f5171507 100644 --- a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java +++ b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java @@ -1,28 +1,25 @@ - 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.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * @author Loki */ -public final class ChosenOfMarkov extends CardImpl { +public final class ChosenOfMarkov extends TransformingDoubleFacedCard { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Vampire you control"); static { @@ -31,27 +28,28 @@ public final class ChosenOfMarkov extends CardImpl { } public ChosenOfMarkov(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{2}{B}", + "Markov's Servant", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B"); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + // Chosen of Markov + this.getLeftHalfCard().setPT(2, 2); - this.secondSideCardClazz = mage.cards.m.MarkovsServant.class; - - // {tap}, Tap an untapped Vampire you control: Transform Chosen of Markov. - this.addAbility(new TransformAbility()); + // {T}, Tap an untapped Vampire you control: Transform Chosen of Markov. Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new TapSourceCost()); ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Markov's Servant + this.getRightHalfCard().setPT(4, 4); } private ChosenOfMarkov(final ChosenOfMarkov card) { super(card); } - @Override - public ChosenOfMarkov copy() { + @Override public ChosenOfMarkov copy() { return new ChosenOfMarkov(this); } } diff --git a/Mage.Sets/src/mage/cards/c/ChromeHostHulk.java b/Mage.Sets/src/mage/cards/c/ChromeHostHulk.java deleted file mode 100644 index 96aa262eeb4..00000000000 --- a/Mage.Sets/src/mage/cards/c/ChromeHostHulk.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; -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 ChromeHostHulk extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); - - static { - filter.add(AnotherPredicate.instance); - } - - public ChromeHostHulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.TROLL); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlue(true); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Chrome Host Hulk attacks, up to one other target creature has base power and toughness 5/5 until end of turn. - Ability ability = new AttacksTriggeredAbility( - new SetBasePowerToughnessTargetEffect(5, 5, Duration.EndOfTurn) - ); - ability.addTarget(new TargetPermanent(0, 1, filter)); - this.addAbility(ability); - } - - private ChromeHostHulk(final ChromeHostHulk card) { - super(card); - } - - @Override - public ChromeHostHulk copy() { - return new ChromeHostHulk(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/Cindervines.java b/Mage.Sets/src/mage/cards/c/Cindervines.java index aa6108c9ea3..b6a1ea1e6aa 100644 --- a/Mage.Sets/src/mage/cards/c/Cindervines.java +++ b/Mage.Sets/src/mage/cards/c/Cindervines.java @@ -31,7 +31,7 @@ public final class Cindervines extends CardImpl { // Whenever an opponent casts a noncreature spell, Cindervines deals 1 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player"), + Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/c/CipherboundSpirit.java b/Mage.Sets/src/mage/cards/c/CipherboundSpirit.java deleted file mode 100644 index 6046bb3bbfb..00000000000 --- a/Mage.Sets/src/mage/cards/c/CipherboundSpirit.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.CanBlockOnlyFlyingAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DrawDiscardControllerEffect; -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 CipherboundSpirit extends CardImpl { - - public CipherboundSpirit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Cipherbound Spirit can block only creatures with flying. - this.addAbility(new CanBlockOnlyFlyingAbility()); - - // {3}{U}: Draw two cards, then discard a card. - this.addAbility(new SimpleActivatedAbility( - new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl<>("{3}{U}") - )); - } - - private CipherboundSpirit(final CipherboundSpirit card) { - super(card); - } - - @Override - public CipherboundSpirit copy() { - return new CipherboundSpirit(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java index 9d9315204fe..a0c955d1e80 100644 --- a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java +++ b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java @@ -1,15 +1,20 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.AttackedThisTurnSourceCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -22,23 +27,33 @@ import java.util.UUID; /** * @author nantuko */ -public final class CivilizedScholar extends CardImpl { +public final class CivilizedScholar extends TransformingDoubleFacedCard { + + private static final Condition condition = new InvertCondition( + AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn" + ); public CivilizedScholar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ADVISOR); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ADVISOR}, "{2}{U}", + "Homicidal Brute", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MUTANT}, "R"); - this.secondSideCardClazz = mage.cards.h.HomicidalBrute.class; + // Civilized Scholar + this.getLeftHalfCard().setPT(0, 1); - this.power = new MageInt(0); - this.toughness = new MageInt(1); - - // {tap}: Draw a card, then discard a card. If a creature card is discarded this way, untap Civilized Scholar, then transform it. + // {T}: Draw a card, then discard a card. If a creature card is discarded this way, untap Civilized Scholar, then transform it. Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); ability.addEffect(new CivilizedScholarEffect()); - this.addAbility(new TransformAbility()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Homicidal Brute + this.getRightHalfCard().setPT(5, 1); + + // At the beginning of your end step, if Homicidal Brute didn't attack this turn, tap Homicidal Brute, then transform it. + TriggeredAbility bruteAbility = new BeginningOfEndStepTriggeredAbility(new TapSourceEffect()); + bruteAbility.addEffect(new TransformSourceEffect().setText(", then transform it")); + this.getRightHalfCard().addAbility(bruteAbility.withInterveningIf(condition)); } private CivilizedScholar(final CivilizedScholar card) { @@ -51,7 +66,6 @@ public final class CivilizedScholar extends CardImpl { } } - class CivilizedScholarEffect extends OneShotEffect { CivilizedScholarEffect() { diff --git a/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java b/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java index 06cc8042fe6..7a5ca0af04b 100644 --- a/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java +++ b/Mage.Sets/src/mage/cards/c/ClayFiredBricks.java @@ -2,13 +2,19 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.game.permanent.token.GnomeToken; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -16,21 +22,33 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ClayFiredBricks extends CardImpl { +public final class ClayFiredBricks extends TransformingDoubleFacedCard { public ClayFiredBricks(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); - this.secondSideCardClazz = mage.cards.c.CosmiumKiln.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{W}", + "Cosmium Kiln", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "W"); + + // Clay-Fired Bricks // When Clay-Fired Bricks enters the battlefield, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. You gain 2 life. Ability ability = new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true) ); ability.addEffect(new GainLifeEffect(2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {5}{W}{W} - this.addAbility(new CraftAbility("{5}{W}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{5}{W}{W}")); + + // Cosmium Kiln + + // When Cosmium Kiln enters the battlefield, create two 1/1 colorless Gnome artifact creature tokens. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 2))); + + // Creatures you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); } private ClayFiredBricks(final ClayFiredBricks card) { diff --git a/Mage.Sets/src/mage/cards/c/CleverDistraction.java b/Mage.Sets/src/mage/cards/c/CleverDistraction.java deleted file mode 100644 index 751b419f195..00000000000 --- a/Mage.Sets/src/mage/cards/c/CleverDistraction.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.c; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.TapTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -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.FilterCreaturePermanent; -import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CleverDistraction extends CardImpl { - - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature defending player controls"); - - static { - filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); - } - - public CleverDistraction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has "Whenever this creature attacks, tap target creature defending player controls." - Ability ability = new AttacksTriggeredAbility(new TapTargetEffect()) - .setTriggerPhrase("Whenever this creature attacks, "); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability, AttachmentType.AURA))); - - // If Clever Distracting would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private CleverDistraction(final CleverDistraction card) { - super(card); - } - - @Override - public CleverDistraction copy() { - return new CleverDistraction(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java index 8a18243df9c..c515b0799ed 100644 --- a/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java +++ b/Mage.Sets/src/mage/cards/c/CliveIfritsDominant.java @@ -1,54 +1,85 @@ package mage.cards.c; -import mage.MageInt; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.condition.Condition; +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.DevotionCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.effects.common.discard.DiscardHandControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class CliveIfritsDominant extends CardImpl { +public final class CliveIfritsDominant extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.LORE, 3); public CliveIfritsDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WARRIOR}, "{4}{R}{R}", + "Ifrit, Warden of Inferno", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.DEMON}, "R"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.i.IfritWardenOfInferno.class; + // Clive, Ifrit's Dominant + this.getLeftHalfCard().setPT(5, 5); // When Clive enters, you may discard your hand, then draw cards equal to your devotion to red. Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect(), true); ability.addEffect(new DrawCardSourceControllerEffect(DevotionCount.R) .setText(", then draw cards equal to your devotion to red")); - this.addAbility(ability.addHint(DevotionCount.R.getHint())); + this.getLeftHalfCard().addAbility(ability.addHint(DevotionCount.R.getHint())); // {4}{R}{R}, {T}: Exile Clive, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{R}{R}") ); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + + // Ifrit, Warden of Inferno + this.getRightHalfCard().setPT(9, 9); + + // Saga (chapters) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Lunge -- Ifrit fights up to one other target creature. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new FightTargetSourceEffect()); + sagaChapterAbility.addTarget(new TargetPermanent(0, 1, filter)); + sagaChapterAbility.withFlavorWord("Lunge"); + }); + + // II, III -- Brimstone -- Add {R}{R}{R}{R}. If Ifrit has three or more lore counters on it, exile it, then return it to the battlefield (front face up.) + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new BasicManaEffect(Mana.RedMana(4))); + sagaChapterAbility.addEffect(new ConditionalOneShotEffect( + new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), condition, + "If {this} has three or more lore counters on it, exile it, then return it to the battlefield. (front face up.)" + )); + sagaChapterAbility.withFlavorWord("Brimstone"); + }); + this.getRightHalfCard().addAbility(sagaAbility); } private CliveIfritsDominant(final CliveIfritsDominant card) { diff --git a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java index def252da59e..bd8a283dccf 100644 --- a/Mage.Sets/src/mage/cards/c/CloisteredYouth.java +++ b/Mage.Sets/src/mage/cards/c/CloisteredYouth.java @@ -1,34 +1,38 @@ - package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author Loki */ -public final class CloisteredYouth extends CardImpl { +public final class CloisteredYouth extends TransformingDoubleFacedCard { public CloisteredYouth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - this.subtype.add(SubType.HUMAN); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{1}{W}", + "Unholy Fiend", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HORROR}, "B"); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.u.UnholyFiend.class; + // Cloistered Youth + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, you may transform Cloistered Youth. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true)); + + // Unholy Fiend + this.getRightHalfCard().setPT(3, 3); + + // At the beginning of your end step, you lose 1 life. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); } private CloisteredYouth(final CloisteredYouth card) { diff --git a/Mage.Sets/src/mage/cards/c/Combust.java b/Mage.Sets/src/mage/cards/c/Combust.java index 7e0703f4087..7a4c5659917 100644 --- a/Mage.Sets/src/mage/cards/c/Combust.java +++ b/Mage.Sets/src/mage/cards/c/Combust.java @@ -2,7 +2,6 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -16,7 +15,8 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** * @@ -36,7 +36,7 @@ public final class Combust extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); // Combust deals 5 damage to target white or blue creature. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(5, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(5).withCantBePrevented()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); // Combust can't be countered. diff --git a/Mage.Sets/src/mage/cards/c/CombustionMan.java b/Mage.Sets/src/mage/cards/c/CombustionMan.java new file mode 100644 index 00000000000..946f62ded84 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CombustionMan.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +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.constants.SuperType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CombustionMan extends CardImpl { + + public CombustionMan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(4); + this.toughness = new MageInt(6); + + // Whenever Combustion Man attacks, destroy target permanent unless its controller has Combustion Man deal damage to them equal to his power. + Ability ability = new AttacksTriggeredAbility(new CombustionManEffect()); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + } + + private CombustionMan(final CombustionMan card) { + super(card); + } + + @Override + public CombustionMan copy() { + return new CombustionMan(this); + } +} + +class CombustionManEffect extends OneShotEffect { + + CombustionManEffect() { + super(Outcome.Benefit); + staticText = "destroy target permanent unless its controller has {this} deal damage to them equal to his power"; + } + + private CombustionManEffect(final CombustionManEffect effect) { + super(effect); + } + + @Override + public CombustionManEffect copy() { + return new CombustionManEffect(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.getControllerId()); + if (player == null || !player.chooseUse( + Outcome.Damage, "Have " + CardUtil.getSourceIdName(game, source) + + " deal damage to you equal to its power?", "If you don't, " + + permanent.getIdName() + " will be destroyed", + "Take damage", "Destroy permanent", source, game + )) { + return permanent.destroy(source, game); + } + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(MageObject::getPower) + .map(MageInt::getValue) + .filter(x -> x > 0) + .filter(x -> player.damage(x, source, game) > 0) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CombustionTechnique.java b/Mage.Sets/src/mage/cards/c/CombustionTechnique.java new file mode 100644 index 00000000000..4586a052905 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CombustionTechnique.java @@ -0,0 +1,48 @@ +package mage.cards.c; + +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.IntPlusDynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CombustionTechnique extends CardImpl { + + private static final DynamicValue xValue = new IntPlusDynamicValue( + 2, new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON)) + ); + + public CombustionTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + this.subtype.add(SubType.LESSON); + + // Combustion Technique deals damage equal to 2 plus the number of Lesson cards in your graveyard to target creature. If that creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(xValue) + .setText("{this} deals damage equal to 2 plus the number of Lesson cards in your graveyard to target creature")); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(LessonsInGraveCondition.getHint()); + } + + private CombustionTechnique(final CombustionTechnique card) { + super(card); + } + + @Override + public CombustionTechnique copy() { + return new CombustionTechnique(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CompassionateHealer.java b/Mage.Sets/src/mage/cards/c/CompassionateHealer.java new file mode 100644 index 00000000000..657ca96d331 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CompassionateHealer.java @@ -0,0 +1,43 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +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 CompassionateHealer extends CardImpl { + + public CompassionateHealer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever this creature becomes tapped, you gain 1 life and scry 1. + Ability ability = new BecomesTappedSourceTriggeredAbility(new GainLifeEffect(1)); + ability.addEffect(new ScryEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private CompassionateHealer(final CompassionateHealer card) { + super(card); + } + + @Override + public CompassionateHealer copy() { + return new CompassionateHealer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java b/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java deleted file mode 100644 index de01acadbb5..00000000000 --- a/Mage.Sets/src/mage/cards/c/CompleatedConjurer.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; -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 CompleatedConjurer extends CardImpl { - - public CompleatedConjurer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.WEIRD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // When this creature transforms into Compleated Conjurer, exile the top card of your library. Until the end of your next turn, you may play that card. - this.addAbility(new TransformIntoSourceTriggeredAbility( - new ExileTopXMayPlayUntilEffect(1, Duration.UntilEndOfYourNextTurn) - )); - } - - private CompleatedConjurer(final CompleatedConjurer card) { - super(card); - } - - @Override - public CompleatedConjurer copy() { - return new CompleatedConjurer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java b/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java index ced78dc8f37..7ba82a0c253 100644 --- a/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java +++ b/Mage.Sets/src/mage/cards/c/ConcealingCurtains.java @@ -1,39 +1,60 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.TargetOpponent; import java.util.UUID; /** * @author TheElk801 */ -public final class ConcealingCurtains extends CardImpl { +public final class ConcealingCurtains extends TransformingDoubleFacedCard { public ConcealingCurtains(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WALL}, "{B}", + "Revealing Eye", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.EYE, SubType.HORROR}, "B"); - this.subtype.add(SubType.WALL); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.r.RevealingEye.class; + // Concealing Curtains + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {2}{B}: Transform Concealing Curtains. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}") )); + + // Revealing Eye + this.getRightHalfCard().setPT(3, 4); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // When this creature transforms into Revealing Eye, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card. + Ability ability = new TransformIntoSourceTriggeredAbility(new RevealingEyeEffect()); + ability.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(ability); } private ConcealingCurtains(final ConcealingCurtains card) { @@ -45,3 +66,43 @@ public final class ConcealingCurtains extends CardImpl { return new ConcealingCurtains(this); } } + +class RevealingEyeEffect extends OneShotEffect { + + RevealingEyeEffect() { + super(Outcome.Discard); + staticText = "target opponent reveals their hand. You may choose a nonland card from it. " + + "If you do, that player discards that card, then draws a card"; + } + + private RevealingEyeEffect(final RevealingEyeEffect effect) { + super(effect); + } + + @Override + public RevealingEyeEffect copy() { + return new RevealingEyeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; + } + opponent.revealCards(source, opponent.getHand(), game); + if (opponent.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) < 1) { + return true; + } + TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_NON_LAND); + controller.choose(outcome, opponent.getHand(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return true; + } + opponent.discard(card, false, source, game); + opponent.drawCards(1, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConductElectricity.java b/Mage.Sets/src/mage/cards/c/ConductElectricity.java index 335dae1cb40..339fddbc851 100644 --- a/Mage.Sets/src/mage/cards/c/ConductElectricity.java +++ b/Mage.Sets/src/mage/cards/c/ConductElectricity.java @@ -1,13 +1,12 @@ package mage.cards.c; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; @@ -20,16 +19,11 @@ public final class ConductElectricity extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Conduct Electricity deals 6 damage to target creature and 2 damage to up to one target creature token. - this.getSpellAbility().addEffect(new DamageTargetEffect( - 6, true, "", true - )); - this.getSpellAbility().addEffect(new DamageTargetEffect( - 2, true, "", true - ).setTargetPointer(new SecondTargetPointer()).setText("and 2 damage to up to one target creature token")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(6, 2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); this.getSpellAbility().addTarget(new TargetPermanent( 0, 1, StaticFilters.FILTER_CREATURE_TOKEN - )); + ).setTargetTag(2)); } private ConductElectricity(final ConductElectricity card) { diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java b/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java deleted file mode 100644 index ec2a8fc337e..00000000000 --- a/Mage.Sets/src/mage/cards/c/ConduitOfEmrakul.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.delayed.AtTheBeginOfMainPhaseDelayedTriggeredAbility; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; -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 LevelX2 - */ -public final class ConduitOfEmrakul extends CardImpl { - - public ConduitOfEmrakul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever Conduit of Emrakul attacks, add {C}{C} at the beginning of your next main phase this turn. - this.addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfMainPhaseDelayedTriggeredAbility( - new AddManaToManaPoolSourceControllerEffect(Mana.GenericMana(2)), false, - TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN - ) - ).setText("add {C}{C} at the beginning of your next main phase this turn"), false)); - } - - private ConduitOfEmrakul(final ConduitOfEmrakul card) { - super(card); - } - - @Override - public ConduitOfEmrakul copy() { - return new ConduitOfEmrakul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java b/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java index 0fdf2d7098f..1e9ea59ceb0 100644 --- a/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java +++ b/Mage.Sets/src/mage/cards/c/ConduitOfStorms.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.MageInt; import mage.Mana; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -9,9 +8,8 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.mana.AddManaToManaPoolSourceControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; @@ -21,19 +19,19 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class ConduitOfStorms extends CardImpl { +public final class ConduitOfStorms extends TransformingDoubleFacedCard { public ConduitOfStorms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{2}{R}", + "Conduit of Emrakul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, ""); - this.secondSideCardClazz = mage.cards.c.ConduitOfEmrakul.class; + // Conduit of Storms + this.getLeftHalfCard().setPT(2, 3); // Whenever Conduit of Storms attacks, add {R} at the beginning of your next main phase this turn. - this.addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfMainPhaseDelayedTriggeredAbility( new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), false, TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN @@ -41,8 +39,18 @@ public final class ConduitOfStorms extends CardImpl { ).setText("add {R} at the beginning of your next main phase this turn"), false)); // {3}{R}{R}: Transform Conduit of Storms. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R}{R}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{R}{R}"))); + + // Conduit of Emrakul + this.getRightHalfCard().setPT(5, 4); + + // Whenever Conduit of Emrakul attacks, add {C}{C} at the beginning of your next main phase this turn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfMainPhaseDelayedTriggeredAbility( + new AddManaToManaPoolSourceControllerEffect(Mana.GenericMana(2)), false, + TargetController.YOU, AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN + ) + ).setText("add {C}{C} at the beginning of your next main phase this turn"), false)); } private ConduitOfStorms(final ConduitOfStorms card) { diff --git a/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java b/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java deleted file mode 100644 index aa342858ef5..00000000000 --- a/Mage.Sets/src/mage/cards/c/ConquerorsFoothold.java +++ /dev/null @@ -1,63 +0,0 @@ - -package mage.cards.c; - -import java.util.UUID; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.DrawDiscardControllerEffect; -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.target.common.TargetCardInYourGraveyard; - -/** - * - * @author TheElk801 - */ -public final class ConquerorsFoothold extends CardImpl { - - public ConquerorsFoothold(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); - - // {2}, {T}: Draw a card, then discard a card. - SimpleActivatedAbility ability = new SimpleActivatedAbility( - new DrawDiscardControllerEffect(), - new ManaCostsImpl<>("{2}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - - // {4}, {T}: Draw a card. - SimpleActivatedAbility ability2 = new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(1), - new ManaCostsImpl<>("{4}")); - ability2.addCost(new TapSourceCost()); - this.addAbility(ability2); - - // {6}, {T}: Return target card from your graveyard to your hand. - SimpleActivatedAbility ability3 = new SimpleActivatedAbility( - new ReturnFromGraveyardToHandTargetEffect(), - new ManaCostsImpl<>("{6}")); - ability3.addCost(new TapSourceCost()); - ability3.addTarget(new TargetCardInYourGraveyard()); - this.addAbility(ability3); - } - - private ConquerorsFoothold(final ConquerorsFoothold card) { - super(card); - } - - @Override - public ConquerorsFoothold copy() { - return new ConquerorsFoothold(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java b/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java index 7c8bcf607a3..dc788fa0b5a 100644 --- a/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java +++ b/Mage.Sets/src/mage/cards/c/ConquerorsGalleon.java @@ -1,48 +1,69 @@ package mage.cards.c; -import mage.MageInt; -import mage.constants.Pronoun; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.*; import mage.abilities.keyword.CrewAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Pronoun; import mage.constants.PutCards; import mage.constants.SubType; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class ConquerorsGalleon extends CardImpl { +public final class ConquerorsGalleon extends TransformingDoubleFacedCard { public ConquerorsGalleon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "{4}", + "Conqueror's Foothold", + new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(10); + // Conqueror's Galleon + this.getLeftHalfCard().setPT(2, 10); - this.secondSideCardClazz = mage.cards.c.ConquerorsFoothold.class; - - // When Conqueror's Galleon attacks, exile it at the end of combat, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksTriggeredAbility( + // When Conqueror's Galleon attacks, exile it at end of combat, then return it to the battlefield transformed under your control. + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility( new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( new ExileAndReturnSourceEffect( PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.IT, true ) - )), false, "When {this} attacks, exile it at end of combat, " + - "then return it to the battlefield transformed under your control." + )), false, "When {this} attacks, exile it at end of combat, then return it to the battlefield transformed under your control." )); // Crew 4 - this.addAbility(new CrewAbility(4)); + this.getLeftHalfCard().addAbility(new CrewAbility(4)); + + + // Conqueror's Foothold + // {T}: Add {C}. + this.getRightHalfCard().addAbility(new ColorlessManaAbility()); + + // {2}, {T}: Draw a card, then discard a card. + SimpleActivatedAbility ability = new SimpleActivatedAbility(new DrawDiscardControllerEffect(), new ManaCostsImpl<>("{2}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); + + // {4}, {T}: Draw a card. + SimpleActivatedAbility ability2 = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{4}")); + ability2.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability2); + + // {6}, {T}: Return target card from your graveyard to your hand. + SimpleActivatedAbility ability3 = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{6}")); + ability3.addCost(new TapSourceCost()); + ability3.addTarget(new TargetCardInYourGraveyard()); + this.getRightHalfCard().addAbility(ability3); } private ConquerorsGalleon(final ConquerorsGalleon card) { diff --git a/Mage.Sets/src/mage/cards/c/ConsumingSepulcher.java b/Mage.Sets/src/mage/cards/c/ConsumingSepulcher.java deleted file mode 100644 index 7499d76d724..00000000000 --- a/Mage.Sets/src/mage/cards/c/ConsumingSepulcher.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.c; - -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ConsumingSepulcher extends CardImpl { - - public ConsumingSepulcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - this.color.setBlack(true); - - // At the beginning of your upkeep, each opponent loses 1 life and you gain 1 life. - Ability ability = new BeginningOfUpkeepTriggeredAbility( - new LoseLifeOpponentsEffect(1) - ); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private ConsumingSepulcher(final ConsumingSepulcher card) { - super(card); - } - - @Override - public ConsumingSepulcher copy() { - return new ConsumingSepulcher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConvictedKiller.java b/Mage.Sets/src/mage/cards/c/ConvictedKiller.java index ed0602e0025..e98aa4030a9 100644 --- a/Mage.Sets/src/mage/cards/c/ConvictedKiller.java +++ b/Mage.Sets/src/mage/cards/c/ConvictedKiller.java @@ -1,40 +1,38 @@ package mage.cards.c; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author fireshoes */ -public final class ConvictedKiller extends CardImpl { +public final class ConvictedKiller extends TransformingDoubleFacedCard { public ConvictedKiller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}", + "Branded Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.b.BrandedHowler.class; + // Convicted Killer + this.getLeftHalfCard().setPT(2, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Convicted Killer. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Branded Howler + this.getRightHalfCard().setPT(4, 4); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Branded Howler. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } - private ConvictedKiller(final ConvictedKiller card) { - super(card); - } - - @Override - public ConvictedKiller copy() { - return new ConvictedKiller(this); - } + private ConvictedKiller(final ConvictedKiller card) { super(card); } + @Override public ConvictedKiller copy() { return new ConvictedKiller(this); } } diff --git a/Mage.Sets/src/mage/cards/c/CookingCampsite.java b/Mage.Sets/src/mage/cards/c/CookingCampsite.java deleted file mode 100644 index a85066abeb2..00000000000 --- a/Mage.Sets/src/mage/cards/c/CookingCampsite.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.c; - -import java.util.UUID; - -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.ManaCostsImpl; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.mana.WhiteManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.counters.CounterType; -import mage.filter.StaticFilters; - -/** - * @author balazskristof - */ -public final class CookingCampsite extends CardImpl { - - public CookingCampsite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // {T}: Add {W}. - this.addAbility(new WhiteManaAbility()); - - // {3}, {T}, Sacrifice an artifact: Put a +1/+1 counter on each creature you control. Activate only as a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility( - new AddCountersAllEffect(CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE), new ManaCostsImpl<>("{3}") - ); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_AN)); - this.addAbility(ability); - } - - private CookingCampsite(final CookingCampsite card) { - super(card); - } - - @Override - public CookingCampsite copy() { - return new CookingCampsite(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CopperTablet.java b/Mage.Sets/src/mage/cards/c/CopperTablet.java index 308d02063d0..240d72dc1ab 100644 --- a/Mage.Sets/src/mage/cards/c/CopperTablet.java +++ b/Mage.Sets/src/mage/cards/c/CopperTablet.java @@ -20,7 +20,7 @@ public final class CopperTablet extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); // At the beginning of each player's upkeep, Copper Tablet deals 1 damage to that player. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "that player"), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("that player"), false)); } private CopperTablet(final CopperTablet card) { diff --git a/Mage.Sets/src/mage/cards/c/CosmiumCatalyst.java b/Mage.Sets/src/mage/cards/c/CosmiumCatalyst.java deleted file mode 100644 index 292bc3b8620..00000000000 --- a/Mage.Sets/src/mage/cards/c/CosmiumCatalyst.java +++ /dev/null @@ -1,98 +0,0 @@ -package mage.cards.c; - -import java.util.UUID; - -import mage.MageObject; -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.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInExile; -import mage.util.CardUtil; - -/** - * Cosmium Catalyst - * Artifact - * {1}{R}, {T}: Choose an exiled card used to craft Cosmium Catalyst at random. You may cast that card without paying its mana cost. - * - * @author DominionSpy - */ -public class CosmiumCatalyst extends CardImpl { - - public CosmiumCatalyst(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.nightCard = true; - this.color.setRed(true); - - // {1}{R}, {T}: Choose an exiled card used to craft Cosmium Catalyst at random. You may cast that card without paying its mana cost. - Ability ability = new SimpleActivatedAbility(new CosmiumCatalystEffect(), new ManaCostsImpl<>("{1}{R}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private CosmiumCatalyst(CosmiumCatalyst card) { - super(card); - } - - @Override - public CosmiumCatalyst copy() { - return new CosmiumCatalyst(this); - } -} - -class CosmiumCatalystEffect extends OneShotEffect { - - CosmiumCatalystEffect() { - super(Outcome.PlayForFree); - this.staticText = "Choose an exiled card used to craft {this} at random." + - " You may cast that card without paying its mana cost."; - } - - private CosmiumCatalystEffect(CosmiumCatalystEffect effect) { - super(effect); - } - - @Override - public CosmiumCatalystEffect copy() { - return new CosmiumCatalystEffect(this); - } - - @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; - } - - Target target = new TargetCardInExile(StaticFilters.FILTER_CARD, - CardUtil.getExileZoneId(game, source.getSourceId(), - game.getState().getZoneChangeCounter(source.getSourceId()) - 2 - )); - target.withNotTarget(true); - target.setRandom(true); - if (!target.canChoose(controller.getId(), source, game)) { - return true; - } - target.chooseTarget(outcome, controller.getId(), source, game); - Card chosenCard = game.getCard(target.getFirstTarget()); - if (chosenCard != null) { - CardUtil.castSpellWithAttributesForFree(controller, source, game, chosenCard); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CosmiumKiln.java b/Mage.Sets/src/mage/cards/c/CosmiumKiln.java deleted file mode 100644 index 08db82019b9..00000000000 --- a/Mage.Sets/src/mage/cards/c/CosmiumKiln.java +++ /dev/null @@ -1,41 +0,0 @@ -package mage.cards.c; - -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -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.game.permanent.token.GnomeToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CosmiumKiln extends CardImpl { - - public CosmiumKiln(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.nightCard = true; - this.color.setWhite(true); - - // When Cosmium Kiln enters the battlefield, create two 1/1 colorless Gnome artifact creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 2))); - - // Creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); - } - - private CosmiumKiln(final CosmiumKiln card) { - super(card); - } - - @Override - public CosmiumKiln copy() { - return new CosmiumKiln(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java index c9372e1d538..3cd865e93c6 100644 --- a/Mage.Sets/src/mage/cards/c/CovertCutpurse.java +++ b/Mage.Sets/src/mage/cards/c/CovertCutpurse.java @@ -1,12 +1,13 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; @@ -20,40 +21,44 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CovertCutpurse extends CardImpl { - - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature you don't control that was dealt damage this turn"); +public final class CovertCutpurse extends TransformingDoubleFacedCard { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature you don't control that was dealt damage this turn"); static { filter.add(TargetController.NOT_YOU.getControllerPredicate()); filter.add(WasDealtDamageThisTurnPredicate.instance); } public CovertCutpurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{2}{B}", + "Covetous Geist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.ROGUE}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.CovetousGeist.class; + // Covert Cutpurse + this.getLeftHalfCard().setPT(2, 1); // When Covert Cutpurse enters the battlefield, destroy target creature you don't control that was dealt damage this turn. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {4}{B} - this.addAbility(new DisturbAbility(this, "{4}{B}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{B}")); + + // Covetous Geist + this.getRightHalfCard().setPT(2, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // If Covetous Geist would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } - private CovertCutpurse(final CovertCutpurse card) { - super(card); - } - - @Override - public CovertCutpurse copy() { - return new CovertCutpurse(this); - } + private CovertCutpurse(final CovertCutpurse card) { super(card); } + @Override public CovertCutpurse copy() { return new CovertCutpurse(this); } } diff --git a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java index 1fd63048184..319d6b7d018 100644 --- a/Mage.Sets/src/mage/cards/c/CovetousCastaway.java +++ b/Mage.Sets/src/mage/cards/c/CovetousCastaway.java @@ -1,35 +1,53 @@ package mage.cards.c; -import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class CovetousCastaway extends CardImpl { +public final class CovetousCastaway extends TransformingDoubleFacedCard { public CovetousCastaway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{1}{U}", + "Ghostly Castigator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.g.GhostlyCastigator.class; + + // Covetous Castaway + this.getLeftHalfCard().setPT(1, 3); // When Covetous Castaway dies, mill three cards. - this.addAbility(new DiesSourceTriggeredAbility(new MillCardsControllerEffect(3))); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new MillCardsControllerEffect(3))); // Disturb {3}{U}{U} - this.addAbility(new DisturbAbility(this, "{3}{U}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{U}{U}")); + + // Ghostly Castigator + this.getRightHalfCard().setPT(3, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When Ghostly Castigator enters the battlefield, you may shuffle up to three target cards from your graveyard into your library. + EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ShuffleIntoLibraryTargetEffect(), true); + ability.addTarget(new TargetCardInYourGraveyard(0, 3)); + this.getRightHalfCard().addAbility(ability); + + // If Ghostly Castigator would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private CovetousCastaway(final CovetousCastaway card) { diff --git a/Mage.Sets/src/mage/cards/c/CovetousGeist.java b/Mage.Sets/src/mage/cards/c/CovetousGeist.java deleted file mode 100644 index 7dd65c1bb4f..00000000000 --- a/Mage.Sets/src/mage/cards/c/CovetousGeist.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DisturbAbility; -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 CovetousGeist extends CardImpl { - - public CovetousGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // If Covetous Geist would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private CovetousGeist(final CovetousGeist card) { - super(card); - } - - @Override - public CovetousGeist copy() { - return new CovetousGeist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java b/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java new file mode 100644 index 00000000000..ffb223b38f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrackedEarthTechnique.java @@ -0,0 +1,43 @@ +package mage.cards.c; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledLandPermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrackedEarthTechnique extends CardImpl { + + public CrackedEarthTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); + + this.subtype.add(SubType.LESSON); + + // Earthbend 3, then earthbend 3. You gain 3 life. + this.getSpellAbility().addEffect(new EarthbendTargetEffect(3, false)); + this.getSpellAbility().addEffect(new EarthbendTargetEffect(3, false) + .concatBy(", then") + .setTargetPointer(new SecondTargetPointer()) + ); + this.getSpellAbility().addTarget(new TargetControlledLandPermanent().withChooseHint("first target")); + this.getSpellAbility().addTarget(new TargetControlledLandPermanent().withChooseHint("second target")); + this.getSpellAbility().addEffect(new GainLifeEffect(3)); + } + + private CrackedEarthTechnique(final CrackedEarthTechnique card) { + super(card); + } + + @Override + public CrackedEarthTechnique copy() { + return new CrackedEarthTechnique(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CradleOfVitality.java b/Mage.Sets/src/mage/cards/c/CradleOfVitality.java index 9cf5689a0f6..9fc3fdfb0d3 100644 --- a/Mage.Sets/src/mage/cards/c/CradleOfVitality.java +++ b/Mage.Sets/src/mage/cards/c/CradleOfVitality.java @@ -27,7 +27,7 @@ public final class CradleOfVitality extends CardImpl { new AddCountersTargetEffect(CounterType.P1P1.createInstance(), SavedGainedLifeValue.MANY) .setText("put a +1/+1 counter on target creature for each 1 life you gained"), new ManaCostsImpl<>("{1}{W}") - ), false, true); + ), false); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CragcrownPathway.java b/Mage.Sets/src/mage/cards/c/CragcrownPathway.java index 4834947b805..97926995e49 100644 --- a/Mage.Sets/src/mage/cards/c/CragcrownPathway.java +++ b/Mage.Sets/src/mage/cards/c/CragcrownPathway.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; import mage.cards.CardSetInfo; @@ -27,7 +26,6 @@ public final class CragcrownPathway extends ModalDoubleFacedCard { // {T}: Add {R}. this.getLeftHalfCard().addAbility(new RedManaAbility()); - this.getLeftHalfCard().addAbility(new TransformAbility()); // 2. // Timbercrown Pathway diff --git a/Mage.Sets/src/mage/cards/c/CrashingWave.java b/Mage.Sets/src/mage/cards/c/CrashingWave.java new file mode 100644 index 00000000000..e3695a1bebb --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashingWave.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapTargetEffect; +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.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPermanentAmount; +import mage.target.targetadjustment.XTargetsCountAdjuster; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrashingWave extends CardImpl { + + public CrashingWave(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{U}"); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Tap up to X target creatures, then distribute three stun counters among tapped creatures your opponents control. + this.getSpellAbility().addEffect(new TapTargetEffect("tap up to X target creatures")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); + this.getSpellAbility().addEffect(new CrashingWaveEffect()); + } + + private CrashingWave(final CrashingWave card) { + super(card); + } + + @Override + public CrashingWave copy() { + return new CrashingWave(this); + } +} + +class CrashingWaveEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("tapped creatures your opponents control"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + CrashingWaveEffect() { + super(Outcome.Benefit); + staticText = ", then distribute three stun counters among tapped creatures your opponents control"; + } + + private CrashingWaveEffect(final CrashingWaveEffect effect) { + super(effect); + } + + @Override + public CrashingWaveEffect copy() { + return new CrashingWaveEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !game.getBattlefield().contains(filter, source.getControllerId(), source, game, 1)) { + return false; + } + TargetPermanentAmount target = new TargetPermanentAmount(3, 1, filter); + target.withNotTarget(true); + player.chooseTarget(outcome, target, source, game); + for (UUID targetId : target.getTargets()) { + Optional.ofNullable(targetId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.addCounters( + CounterType.STUN.createInstance(target.getTargetAmount(targetId)), source, game + )); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CravenHulk.java b/Mage.Sets/src/mage/cards/c/CravenHulk.java index 1eed5276fa9..2bfec9a8978 100644 --- a/Mage.Sets/src/mage/cards/c/CravenHulk.java +++ b/Mage.Sets/src/mage/cards/c/CravenHulk.java @@ -1,7 +1,8 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantBlockAloneSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,7 +24,7 @@ public final class CravenHulk extends CardImpl { this.toughness = new MageInt(4); // Craven Hulk can't block alone. - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new SimpleStaticAbility(new CantBlockAloneSourceEffect())); } private CravenHulk(final CravenHulk card) { diff --git a/Mage.Sets/src/mage/cards/c/CreepingCrystalCoating.java b/Mage.Sets/src/mage/cards/c/CreepingCrystalCoating.java new file mode 100644 index 00000000000..08ddafcbd0b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CreepingCrystalCoating.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +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.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +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.game.permanent.token.FoodToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CreepingCrystalCoating extends CardImpl { + + public CreepingCrystalCoating(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)); + + // Enchanted creature gets +0/+3 and has "Whenever this creature attacks, create a Food token." + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(0, 3)); + ability.addEffect(new GainAbilityAttachedEffect( + new AttacksTriggeredAbility(new CreateTokenEffect(new FoodToken())), AttachmentType.AURA + ).setText("and has \"Whenever this creature attacks, create a Food token.\"")); + this.addAbility(ability); + } + + private CreepingCrystalCoating(final CreepingCrystalCoating card) { + super(card); + } + + @Override + public CreepingCrystalCoating copy() { + return new CreepingCrystalCoating(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CreepingInn.java b/Mage.Sets/src/mage/cards/c/CreepingInn.java deleted file mode 100644 index 106c64a1076..00000000000 --- a/Mage.Sets/src/mage/cards/c/CreepingInn.java +++ /dev/null @@ -1,109 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PhaseOutSourceEffect; -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.StaticFilters; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author LePwnerer - */ -public final class CreepingInn extends CardImpl { - - public CreepingInn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HORROR); - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(3); - this.toughness = new MageInt(7); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever Creeping Inn attacks, you may exile a creature card from your graveyard. - // If you do, each opponent loses X life and you gain X life, - // where X is the number of creature cards exiled with Creeping Inn. - this.addAbility(new AttacksTriggeredAbility(new CreepingInnEffect())); - - // {4}: Creeping Inn phases out. - this.addAbility(new SimpleActivatedAbility(new PhaseOutSourceEffect(), new ManaCostsImpl<>("{4}"))); - } - - private CreepingInn(final CreepingInn card) { - super(card); - } - - @Override - public CreepingInn copy() { - return new CreepingInn(this); - } -} - -class CreepingInnEffect extends OneShotEffect { - - CreepingInnEffect() { - super(Outcome.Exile); - this.staticText = "you may exile a creature card from your graveyard. " + - "If you do, each opponent loses X life and you gain X life, " + - "where X is the number of creature cards exiled with {this}."; - } - - private CreepingInnEffect(final CreepingInnEffect effect) { - super(effect); - } - - @Override - public CreepingInnEffect copy() { - return new CreepingInnEffect(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) { - UUID exileId = CardUtil.getExileZoneId(game, source); - TargetCardInGraveyard target = new TargetCardInGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); - target.withNotTarget(true); - 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; - player.moveCardsToExile(cardChosen, source, game, true, exileId, permanent.getName()); - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null) { - for (UUID cardId : exile) { - lifeAmount++; - } - } - for (UUID playerId : game.getOpponents(source.getControllerId())) { - game.getPlayer(playerId).loseLife(lifeAmount, game, source, false); - } - player.gainLife(lifeAmount, game, source); - } - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CrescentIslandTemple.java b/Mage.Sets/src/mage/cards/c/CrescentIslandTemple.java new file mode 100644 index 00000000000..8349eeea9fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrescentIslandTemple.java @@ -0,0 +1,58 @@ +package mage.cards.c; + +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.permanent.token.MonkRedToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrescentIslandTemple extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SHRINE); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Shrines you control", xValue); + private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.SHRINE, "another Shrine you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public CrescentIslandTemple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // When Crescent Island Temple enters, for each Shrine you control, create a 1/1 red Monk creature token with prowess. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MonkRedToken(), xValue) + .setText("for each Shrine you control, create a 1/1 red Monk creature token with prowess")).addHint(hint)); + + // Whenever another Shrine you control enters, create a 1/1 red Monk creature token with prowess. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new CreateTokenEffect(new MonkRedToken()), filter2)); + } + + private CrescentIslandTemple(final CrescentIslandTemple card) { + super(card); + } + + @Override + public CrescentIslandTemple copy() { + return new CrescentIslandTemple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CruelAdministrator.java b/Mage.Sets/src/mage/cards/c/CruelAdministrator.java new file mode 100644 index 00000000000..f91b2c39df5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CruelAdministrator.java @@ -0,0 +1,54 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.common.RaidCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.counters.CounterType; +import mage.game.permanent.token.SoldierFirebendingToken; +import mage.watchers.common.PlayerAttackedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CruelAdministrator extends CardImpl { + + public CruelAdministrator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Raid -- This creature enters with a +1/+1 counter on it if you attacked this turn. + this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), RaidCondition.instance, "" + ), "with a +1/+1 counter on it if you attacked this turn") + .setAbilityWord(AbilityWord.RAID) + .addHint(RaidHint.instance), new PlayerAttackedWatcher()); + + // Whenever this creature attacks, create a 2/2 red Soldier creature token with firebending 1. + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new SoldierFirebendingToken()))); + } + + private CruelAdministrator(final CruelAdministrator card) { + super(card); + } + + @Override + public CruelAdministrator copy() { + return new CruelAdministrator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrumblingSanctuary.java b/Mage.Sets/src/mage/cards/c/CrumblingSanctuary.java index 76cff5e1ca2..184ccc524e7 100644 --- a/Mage.Sets/src/mage/cards/c/CrumblingSanctuary.java +++ b/Mage.Sets/src/mage/cards/c/CrumblingSanctuary.java @@ -1,19 +1,21 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import java.util.UUID; + /** * * @author LoneFox @@ -38,10 +40,10 @@ public final class CrumblingSanctuary extends CardImpl { } } -class CrumblingSanctuaryEffect extends PreventionEffectImpl { +class CrumblingSanctuaryEffect extends ReplacementEffectImpl { CrumblingSanctuaryEffect() { - super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); + super(Duration.WhileOnBattlefield, Outcome.PreventDamage); staticText = "If damage would be dealt to a player, that player exiles that many cards from the top of their library instead."; } @@ -59,16 +61,18 @@ class CrumblingSanctuaryEffect extends PreventionEffectImpl { int amount = event.getAmount(); Player player = game.getPlayer(event.getTargetId()); if(player != null) { - preventDamageAction(event, source, game); player.moveCards(player.getLibrary().getTopCards(game, amount), Zone.EXILED, source, game); - return true; } - return false; + return true; + } + + @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 super.applies(event, source, game) && (game.getPlayer(event.getTargetId()) != null); + return true; } - } diff --git a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java index ec264beae69..46c2288f17f 100644 --- a/Mage.Sets/src/mage/cards/c/CryptolithFragment.java +++ b/Mage.Sets/src/mage/cards/c/CryptolithFragment.java @@ -1,18 +1,22 @@ package mage.cards.c; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.LifeCompareCondition; import mage.abilities.effects.common.LoseLifeAllPlayersEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.mana.AnyColorManaAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.TargetController; import java.util.UUID; @@ -20,26 +24,39 @@ import java.util.UUID; /** * @author fireshoes */ -public final class CryptolithFragment extends CardImpl { +public final class CryptolithFragment extends TransformingDoubleFacedCard { private static final Condition condition = new LifeCompareCondition(TargetController.EACH_PLAYER, ComparisonType.OR_LESS, 10); public CryptolithFragment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - - this.secondSideCardClazz = mage.cards.a.AuroraOfEmrakul.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Aurora of Emrakul", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.REFLECTION}, ""); + // Cryptolith Fragment // Cryptolith Fragment enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add one mana of any color. Each player loses 1 life. Ability anyColorManaAbility = new AnyColorManaAbility(); anyColorManaAbility.addEffect(new LoseLifeAllPlayersEffect(1)); - this.addAbility(anyColorManaAbility); + this.getLeftHalfCard().addAbility(anyColorManaAbility); // At the beginning of your upkeep, if each player has 10 or less life, transform Cryptolith Fragment. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + + // Aurora of Emrakul + this.getRightHalfCard().setPT(1, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Aurora of Emrakul attacks, each opponent loses 3 life. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(3), false)); } private CryptolithFragment(final CryptolithFragment card) { diff --git a/Mage.Sets/src/mage/cards/c/CrystalFragments.java b/Mage.Sets/src/mage/cards/c/CrystalFragments.java index 145a755ba55..8a84aefb02a 100644 --- a/Mage.Sets/src/mage/cards/c/CrystalFragments.java +++ b/Mage.Sets/src/mage/cards/c/CrystalFragments.java @@ -1,42 +1,65 @@ package mage.cards.c; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.PreventAllDamageToAllEffect; +import mage.abilities.effects.common.TapAllEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class CrystalFragments extends CardImpl { +public final class CrystalFragments extends TransformingDoubleFacedCard { public CrystalFragments(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{W}"); - - this.subtype.add(SubType.EQUIPMENT); - this.secondSideCardClazz = mage.cards.s.SummonAlexander.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{W}", + "Summon: Alexander", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.CONSTRUCT}, "W"); + // Crystal Fragments // Equipped creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); // {5}{W}{W}: Exile this Equipment, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{5}{W}{W}") )); // Equip {1} - this.addAbility(new EquipAbility(1)); + this.getLeftHalfCard().addAbility(new EquipAbility(1)); + + // Summon: Alexander + this.getRightHalfCard().setPT(4, 3); + + // Saga setup (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()).withShowSacText(true); + + // I, II -- Prevent all damage that would be dealt to creatures you control this turn. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + chapterAbility -> chapterAbility.addEffect(new PreventAllDamageToAllEffect( + Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED + ))); + + // III -- Tap all creatures your opponents control. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, + chapterAbility -> chapterAbility.addEffect(new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); + + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private CrystalFragments(final CrystalFragments card) { diff --git a/Mage.Sets/src/mage/cards/l/LanternsLift.java b/Mage.Sets/src/mage/cards/c/CrystallineArmor.java similarity index 56% rename from Mage.Sets/src/mage/cards/l/LanternsLift.java rename to Mage.Sets/src/mage/cards/c/CrystallineArmor.java index 7cb53c9d83e..4a39d5fb10a 100644 --- a/Mage.Sets/src/mage/cards/l/LanternsLift.java +++ b/Mage.Sets/src/mage/cards/c/CrystallineArmor.java @@ -1,16 +1,19 @@ -package mage.cards.l; +package mage.cards.c; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.EnchantAbility; -import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; 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; @@ -19,14 +22,12 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LanternsLift extends CardImpl { +public final class CrystallineArmor extends CardImpl { - public LanternsLift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); + public CrystallineArmor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); @@ -34,25 +35,22 @@ public final class LanternsLift extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget)); - // Enchanted creature gets +1/+1 and has flying. + // Enchanted creature gets +1/+1 for each land you control and has trample. Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( - 1, 1, Duration.WhileOnBattlefield - )); + LandsYouControlCount.instance, LandsYouControlCount.instance + ).setText("enchanted creature gets +1/+1 for each land you control")); ability.addEffect(new GainAbilityAttachedEffect( - FlyingAbility.getInstance(), AttachmentType.AURA - ).setText("and has flying")); + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); this.addAbility(ability); - - // If Lanterns' Lift would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); } - private LanternsLift(final LanternsLift card) { + private CrystallineArmor(final CrystallineArmor card) { super(card); } @Override - public LanternsLift copy() { - return new LanternsLift(this); + public CrystallineArmor copy() { + return new CrystallineArmor(this); } } diff --git a/Mage.Sets/src/mage/cards/c/CrystallineResonance.java b/Mage.Sets/src/mage/cards/c/CrystallineResonance.java index 8167b56cd06..47339a11835 100644 --- a/Mage.Sets/src/mage/cards/c/CrystallineResonance.java +++ b/Mage.Sets/src/mage/cards/c/CrystallineResonance.java @@ -8,9 +8,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.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.target.TargetPermanent; import mage.util.functions.CopyApplier; @@ -22,12 +20,6 @@ import java.util.UUID; */ public final class CrystallineResonance extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public CrystallineResonance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); @@ -54,7 +46,7 @@ public final class CrystallineResonance extends CardImpl { "except it has this ability" ), true ); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_PERMANENT)); return ability; } } diff --git a/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java b/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java deleted file mode 100644 index a10acd8f683..00000000000 --- a/Mage.Sets/src/mage/cards/c/CrystallizedSerah.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.c; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.s.SerahFarron; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class CrystallizedSerah extends CardImpl { - - public CrystallizedSerah(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - this.color.setGreen(true); - this.color.setWhite(true); - - // The first legendary creature spell you cast each turn costs {2} less to cast. - this.addAbility(SerahFarron.makeAbility()); - - // Legendary creatures you control get +2/+2. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 2, 2, Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_LEGENDARY - ))); - } - - private CrystallizedSerah(final CrystallizedSerah card) { - super(card); - } - - @Override - public CrystallizedSerah copy() { - return new CrystallizedSerah(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CunningManeuver.java b/Mage.Sets/src/mage/cards/c/CunningManeuver.java new file mode 100644 index 00000000000..191c046d5ac --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CunningManeuver.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +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.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CunningManeuver extends CardImpl { + + public CunningManeuver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Target creature gets +3/+1 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(3, 1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Create a Clue token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("
")); + } + + private CunningManeuver(final CunningManeuver card) { + super(card); + } + + @Override + public CunningManeuver copy() { + return new CunningManeuver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CunningStrike.java b/Mage.Sets/src/mage/cards/c/CunningStrike.java index e3bdf684b9d..0b1d21da301 100644 --- a/Mage.Sets/src/mage/cards/c/CunningStrike.java +++ b/Mage.Sets/src/mage/cards/c/CunningStrike.java @@ -1,17 +1,14 @@ - package mage.cards.c; -import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; -import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** * @@ -22,14 +19,11 @@ public final class CunningStrike extends CardImpl { public CunningStrike(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{R}"); - // Cunning Strike deals 2 damage to target creature and 2 damage to target player. - this.getSpellAbility().addEffect(new DamageTargetEffect(StaticValue.get(2), true, "", true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Effect effect = new DamageTargetEffect(StaticValue.get(2), true, "", true); - effect.setTargetPointer(new SecondTargetPointer()); - effect.setText("and 2 damage to target player or planeswalker"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); + // Cunning Strike deals 2 damage to target creature and 2 damage to target player or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(2)); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/c/CuombajjWitches.java b/Mage.Sets/src/mage/cards/c/CuombajjWitches.java index 2389a6b11b8..79029a89b03 100644 --- a/Mage.Sets/src/mage/cards/c/CuombajjWitches.java +++ b/Mage.Sets/src/mage/cards/c/CuombajjWitches.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageInt; @@ -12,13 +11,13 @@ 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.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetOpponent; import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.EachTargetPointer; import java.util.UUID; @@ -35,7 +34,7 @@ public final class CuombajjWitches extends CardImpl { this.toughness = new MageInt(3); // {T}: Cuombajj Witches deals 1 damage to any target and 1 damage to any target of an opponent's choice. - Effect effect = new DamageTargetEffect(1); + Effect effect = new DamageTargetEffect(1).setTargetPointer(new EachTargetPointer()); effect.setText("{this} deals 1 damage to any target and 1 damage to any target of an opponent's choice"); Ability ability = new SimpleActivatedAbility(effect, new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CuriousFarmAnimals.java b/Mage.Sets/src/mage/cards/c/CuriousFarmAnimals.java new file mode 100644 index 00000000000..22c98506229 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CuriousFarmAnimals.java @@ -0,0 +1,53 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CuriousFarmAnimals extends CardImpl { + + public CuriousFarmAnimals(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.BOAR); + this.subtype.add(SubType.ELK); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.OX); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When this creature dies, you gain 3 life. + this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(3))); + + // {2}, Sacrifice this creature: Destroy up to one target artifact or enchantment. + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(2)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.addAbility(ability); + } + + private CuriousFarmAnimals(final CuriousFarmAnimals card) { + super(card); + } + + @Override + public CuriousFarmAnimals copy() { + return new CuriousFarmAnimals(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java index b78941496aa..eeea1819109 100644 --- a/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java +++ b/Mage.Sets/src/mage/cards/c/CuriousHomunculus.java @@ -1,21 +1,23 @@ package mage.cards.c; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.ProwessAbility; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; @@ -24,25 +26,35 @@ import java.util.UUID; /** * @author fireshoes */ -public final class CuriousHomunculus extends CardImpl { +public final class CuriousHomunculus extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(3, new FilterInstantOrSorceryCard("instant and/or sorcery cards")); private static final Hint hint = new ValueHint("Instant and sorcery cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY)); + private static final FilterCard filter = new FilterInstantOrSorceryCard("Instant and sorcery spells"); public CuriousHomunculus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.HOMUNCULUS); - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HOMUNCULUS}, "{1}{U}", + "Voracious Reader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.HOMUNCULUS}, ""); - this.secondSideCardClazz = mage.cards.v.VoraciousReader.class; + // Curious Homunculus + this.getLeftHalfCard().setPT(1, 1); // {T}: Add {C}. Spend this mana only to cast an instant or sorcery spell. - this.addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 1, new InstantOrSorcerySpellManaBuilder())); + this.getLeftHalfCard().addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 1, new InstantOrSorcerySpellManaBuilder())); // At the beginning of your upkeep, if there are three or more instant and/or sorcery cards in your graveyard, transform Curious Homunculus. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition).addHint(hint)); + + // Voracious Reader + this.getRightHalfCard().setPT(3, 4); + + // Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + + // Instant and sorcery spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); } private CuriousHomunculus(final CuriousHomunculus card) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java index 1cbb930c7bd..13c506faebd 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java @@ -1,7 +1,6 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AttachEffect; @@ -9,8 +8,11 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; @@ -23,24 +25,24 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class CurseOfLeeches extends CardImpl { +public final class CurseOfLeeches extends TransformingDoubleFacedCard { public CurseOfLeeches(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); - - this.subtype.add(SubType.AURA); - this.subtype.add(SubType.CURSE); - this.secondSideCardClazz = mage.cards.l.LeechingLurker.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "{2}{B}", + "Leeching Lurker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.LEECH, SubType.HORROR}, "B"); + // Curse of Leeches // Enchant player TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getLeftHalfCard().getSpellAbility().addTarget(auraTarget); + this.getLeftHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // As this permanent transforms into Curse of Leeches, attach it to a player. - this.addAbility(new SimpleStaticAbility(new CurseOfLeechesEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CurseOfLeechesEffect())); // At the beginning of enchanted player's upkeep, they lose 1 life and you gain 1 life. ability = new BeginningOfUpkeepTriggeredAbility( @@ -48,10 +50,19 @@ public final class CurseOfLeeches extends CardImpl { false ); ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Leeching Lurker + this.getRightHalfCard().setPT(4, 4); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private CurseOfLeeches(final CurseOfLeeches card) { @@ -75,6 +86,11 @@ class CurseOfLeechesEffect extends ReplacementEffectImpl { super(effect); } + @Override + public CurseOfLeechesEffect copy() { + return new CurseOfLeechesEffect(this); + } + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); @@ -101,9 +117,4 @@ class CurseOfLeechesEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { return source.getSourceId().equals(event.getTargetId()); } - - @Override - public CurseOfLeechesEffect copy() { - return new CurseOfLeechesEffect(this); - } } diff --git a/Mage.Sets/src/mage/cards/c/CutIn.java b/Mage.Sets/src/mage/cards/c/CutIn.java index 9d23e5e6a82..a0d73d9e607 100644 --- a/Mage.Sets/src/mage/cards/c/CutIn.java +++ b/Mage.Sets/src/mage/cards/c/CutIn.java @@ -22,11 +22,7 @@ public final class CutIn extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Cut In deals 4 damage to target creature. - this.getSpellAbility().addEffect( - new DamageTargetEffect(4) - .setUseOnlyTargetPointer(true) - .setTargetPointer(new FirstTargetPointer()) - ); + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Create a Young Hero Role token attached to up to one target creature you control. diff --git a/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java b/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java new file mode 100644 index 00000000000..5b3d1d6ebb2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CycleOfRenewal.java @@ -0,0 +1,39 @@ +package mage.cards.c; + +import mage.abilities.effects.common.SacrificeControllerEffect; +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.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CycleOfRenewal extends CardImpl { + + public CycleOfRenewal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + this.subtype.add(SubType.LESSON); + + // Sacrifice a land. Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle. + this.getSpellAbility().addEffect(new SacrificeControllerEffect(StaticFilters.FILTER_LAND, 1, "")); + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS + ), true)); + } + + private CycleOfRenewal(final CycleOfRenewal card) { + super(card); + } + + @Override + public CycleOfRenewal copy() { + return new CycleOfRenewal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java b/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java deleted file mode 100644 index 1b21a9e9880..00000000000 --- a/Mage.Sets/src/mage/cards/c/CyclonusCybertronianFighter.java +++ /dev/null @@ -1,86 +0,0 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TurnPhase; -import mage.game.Game; -import mage.game.turn.TurnMod; - -import java.util.UUID; - -/** - * @author mllagostera - */ -public final class CyclonusCybertronianFighter extends CardImpl { - - public CyclonusCybertronianFighter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.color.setBlue(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Cyclonus deals combat damage to a player, convert it. - // If you do, there is an additional beginning phase after this phase. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( - new CyclonusCybertronianFighterEffect(), - false - ); - this.addAbility(ability); - } - - private CyclonusCybertronianFighter(final CyclonusCybertronianFighter card) { - super(card); - } - - @Override - public CyclonusCybertronianFighter copy() { - return new CyclonusCybertronianFighter(this); - } -} - -class CyclonusCybertronianFighterEffect extends TransformSourceEffect { - - CyclonusCybertronianFighterEffect() { - super(); - staticText = "transform it. If you do, there is an additional beginning phase after this phase"; - } - - private CyclonusCybertronianFighterEffect(final CyclonusCybertronianFighterEffect effect) { - super(effect); - } - - @Override - public CyclonusCybertronianFighterEffect copy() { - return new CyclonusCybertronianFighterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (!super.apply(game, source)) { - return false; - } - TurnMod beginning = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.BEGINNING); - game.getState().getTurnMods().add(beginning); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java b/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java index d5559695d3d..e54ff1cfdbf 100644 --- a/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java +++ b/Mage.Sets/src/mage/cards/c/CyclonusTheSaboteur.java @@ -1,74 +1,109 @@ -package mage.cards.c; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceMatchesFilterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.keyword.ConniveSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.PowerPredicate; - -import java.util.UUID; - -/** - * @author mllagostera - */ -public final class CyclonusTheSaboteur extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(); - - static { - filter.add(new PowerPredicate(ComparisonType.MORE_THAN,4)); - } - - private static final Condition condition = new SourceMatchesFilterCondition(filter); - - public CyclonusTheSaboteur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.c.CyclonusCybertronianFighter.class; - - // More Than Meets the Eye {5}{U}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{5}{U}{B}")); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Cyclonus deals combat damage to a player, it connives. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( - new ConniveSourceEffect("it"), - false, - true - ); - - // Then if Cyclonus's power is 5 or greater, convert it - ability.addEffect((new ConditionalOneShotEffect( - new TransformSourceEffect(), - condition, - "Then if {this}'s power is 5 or greater, convert it." - ))); - - this.addAbility(ability); - } - - private CyclonusTheSaboteur(final CyclonusTheSaboteur card) { - super(card); - } - - @Override - public CyclonusTheSaboteur copy() { - return new CyclonusTheSaboteur(this); - } -} +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LivingMetalAbility; +import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.turn.TurnMod; + +import java.util.UUID; + +/** + * @author mllagostera + */ +public final class CyclonusTheSaboteur extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent(); + static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN,4)); } + private static final Condition condition = new SourceMatchesFilterCondition(filter); + + public CyclonusTheSaboteur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{2}{U}{B}", + "Cyclonus, Cybertronian Fighter", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "UB"); + + // Cyclonus, the Saboteur + this.getLeftHalfCard().setPT(2, 5); + + // More Than Meets the Eye {5}{U}{B} + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{5}{U}{B}")); + + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Cyclonus deals combat damage to a player, it connives. Then if Cyclonus's power is 5 or greater, convert it. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new ConniveSourceEffect("it"), false, true + ); + ability.addEffect(new ConditionalOneShotEffect( + new TransformSourceEffect(), condition, + "Then if {this}'s power is 5 or greater, convert it." + )); + this.getLeftHalfCard().addAbility(ability); + + // Cyclonus, Cybertronian Fighter + this.getRightHalfCard().setPT(5, 5); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Cyclonus deals combat damage to a player, transform it. If you do, there is an additional beginning phase after this phase. + Ability abilityBack = new DealsCombatDamageToAPlayerTriggeredAbility( + new CyclonusCybertronianFighterEffect(), + false + ); + this.getRightHalfCard().addAbility(abilityBack); + } + + private CyclonusTheSaboteur(final CyclonusTheSaboteur card) { + super(card); + } + + @Override + public CyclonusTheSaboteur copy() { + return new CyclonusTheSaboteur(this); + } +} + +class CyclonusCybertronianFighterEffect extends TransformSourceEffect { + + CyclonusCybertronianFighterEffect() { + super(); + staticText = "convert it. If you do, there is an additional beginning phase after this phase"; + } + + private CyclonusCybertronianFighterEffect(final CyclonusCybertronianFighterEffect effect) { + super(effect); + } + + @Override + public CyclonusCybertronianFighterEffect copy() { + return new CyclonusCybertronianFighterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!super.apply(game, source)) { + return false; + } + TurnMod beginning = new TurnMod(game.getState().getActivePlayerId()).withExtraPhase(TurnPhase.BEGINNING); + game.getState().getTurnMods().add(beginning); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaggerCaster.java b/Mage.Sets/src/mage/cards/d/DaggerCaster.java index aed8e187569..18a7388ae79 100644 --- a/Mage.Sets/src/mage/cards/d/DaggerCaster.java +++ b/Mage.Sets/src/mage/cards/d/DaggerCaster.java @@ -3,14 +3,17 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; 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.filter.StaticFilters; +import mage.game.Game; import java.util.UUID; @@ -28,14 +31,7 @@ public final class DaggerCaster extends CardImpl { this.toughness = new MageInt(3); // When Dagger Caster enters the battlefield, it deals 1 damage to each opponent and 1 damage to each creature your opponents control. - Ability ability = new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect( - 1, TargetController.OPPONENT, "it" - )); - ability.addEffect( - new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) - .setText("and 1 damage to each creature your opponents control") - ); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DaggerCasterEffect())); } private DaggerCaster(final DaggerCaster card) { @@ -47,3 +43,29 @@ public final class DaggerCaster extends CardImpl { return new DaggerCaster(this); } } + +// needed for simultaneous damage +class DaggerCasterEffect extends OneShotEffect { + + DaggerCasterEffect() { + super(Outcome.Damage); + staticText = "it deals 1 damage to each opponent and 1 damage to each creature your opponents control"; + } + + private DaggerCasterEffect(final DaggerCasterEffect effect) { + super(effect); + } + + @Override + public DaggerCasterEffect copy() { + return new DaggerCasterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new DamagePlayersEffect(1, TargetController.OPPONENT, "it").apply(game, source); + new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE).apply(game, source); + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/d/DaiLiAgents.java b/Mage.Sets/src/mage/cards/d/DaiLiAgents.java new file mode 100644 index 00000000000..a5f62bd0d16 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DaiLiAgents.java @@ -0,0 +1,71 @@ +package mage.cards.d; + +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.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.common.TargetControlledLandPermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DaiLiAgents extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creatures you control with +1/+1 counters on them"); + + static { + filter.add(CounterType.P1P1.getPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Creatures you control with +1/+1 counters on them", xValue); + + public DaiLiAgents(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, earthbend 1, then earthbend 1. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(1).setText("earthbend 1")); + ability.addEffect(new EarthbendTargetEffect(1) + .setTargetPointer(new SecondTargetPointer()) + .concatBy(", then")); + ability.addTarget(new TargetControlledLandPermanent().withChooseHint("first target")); + ability.addTarget(new TargetControlledLandPermanent().withChooseHint("second target")); + this.addAbility(ability.addHint(hint)); + + // Whenever this creature attacks, each opponent loses X life and you gain X life, where X is the number of creatures you control with +1/+1 counters on them. + ability = new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(xValue).setText("each opponent loses X life")); + ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the number of creatures you control with +1/+1 counters on them")); + this.addAbility(ability); + } + + private DaiLiAgents(final DaiLiAgents card) { + super(card); + } + + @Override + public DaiLiAgents copy() { + return new DaiLiAgents(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaiLiCensor.java b/Mage.Sets/src/mage/cards/d/DaiLiCensor.java new file mode 100644 index 00000000000..c9c68eb9dcb --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DaiLiCensor.java @@ -0,0 +1,48 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DaiLiCensor extends CardImpl { + + public DaiLiCensor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {1}, Sacrifice another creature: This creature gets +2/+2 until end of turn. Activate only once each turn. + Ability ability = new LimitedTimesPerTurnActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), new GenericManaCost(1) + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private DaiLiCensor(final DaiLiCensor card) { + super(card); + } + + @Override + public DaiLiCensor copy() { + return new DaiLiCensor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaringSleuth.java b/Mage.Sets/src/mage/cards/d/DaringSleuth.java index b6a2e57ab33..765a27080f0 100644 --- a/Mage.Sets/src/mage/cards/d/DaringSleuth.java +++ b/Mage.Sets/src/mage/cards/d/DaringSleuth.java @@ -1,11 +1,12 @@ package mage.cards.d; -import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SacrificePermanentTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.ProwessAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -15,21 +16,30 @@ import java.util.UUID; /** * @author fireshoes */ -public final class DaringSleuth extends CardImpl { +public final class DaringSleuth extends TransformingDoubleFacedCard { public DaringSleuth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{U}", + "Bearer of Overwhelming Truths", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "U"); - this.secondSideCardClazz = mage.cards.b.BearerOfOverwhelmingTruths.class; + // Daring Sleuth + this.getLeftHalfCard().setPT(2, 1); // When you sacrifice a Clue, transform Daring Sleuth. - this.addAbility(new TransformAbility()); - this.addAbility(new SacrificePermanentTriggeredAbility(new TransformSourceEffect(), StaticFilters.FILTER_CONTROLLED_CLUE) - .setTriggerPhrase("When you sacrifice a Clue, ")); + this.getLeftHalfCard().addAbility(new SacrificePermanentTriggeredAbility( + new TransformSourceEffect(), StaticFilters.FILTER_CONTROLLED_CLUE + ).setTriggerPhrase("When you sacrifice a Clue, ")); + + // Bearer of Overwhelming Truths + this.getRightHalfCard().setPT(3, 2); + + // Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + + // Whenever Bearer of Overwhelming Truths deals combat damage to a player, investigate. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new InvestigateEffect(), false)); } private DaringSleuth(final DaringSleuth card) { diff --git a/Mage.Sets/src/mage/cards/d/DarkSphere.java b/Mage.Sets/src/mage/cards/d/DarkSphere.java index e084e635a1a..9ffd6c5f505 100644 --- a/Mage.Sets/src/mage/cards/d/DarkSphere.java +++ b/Mage.Sets/src/mage/cards/d/DarkSphere.java @@ -1,7 +1,6 @@ package mage.cards.d; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -15,7 +14,6 @@ import mage.filter.FilterSource; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.players.Player; import java.util.UUID; @@ -65,22 +63,10 @@ class DarkSpherePreventionEffect extends PreventNextDamageFromChosenSourceEffect @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); DamageEvent damageEvent = (DamageEvent) event; - int damage = damageEvent.getAmount(); - if (controller == null || damage <= 0) { - return false; - } - controller.damage( - (int) Math.ceil(damage / 2.0), damageEvent.getSourceId(), source, game, - damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects() - ); - StringBuilder sb = new StringBuilder(sourceObject != null ? sourceObject.getLogName() : ""); - sb.append(": ").append(damage / 2).append(" damage prevented"); - sb.append(" from ").append(controller.getLogName()); - game.informPlayers(sb.toString()); + amountToPrevent = (int) Math.floor(damageEvent.getAmount() / 2.0); + preventDamageAction(event, source, game); discard(); // only one use - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/d/DarthVader.java b/Mage.Sets/src/mage/cards/d/DarthVader.java deleted file mode 100644 index df674cb3863..00000000000 --- a/Mage.Sets/src/mage/cards/d/DarthVader.java +++ /dev/null @@ -1,99 +0,0 @@ - -package mage.cards.d; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.MenaceAbility; -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 java.util.Iterator; -import java.util.UUID; - -/** - * @author Styxo - */ -public final class DarthVader extends CardImpl { - - public DarthVader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SITH); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Whenever Darth Vader attacks, creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader. - this.addAbility(new AttacksTriggeredAbility(new UnboostCreaturesDefendingPlayerEffect(), false, null, SetTargetPointer.PLAYER)); - } - - private DarthVader(final DarthVader card) { - super(card); - } - - @Override - public DarthVader copy() { - return new DarthVader(this); - } -} - -class UnboostCreaturesDefendingPlayerEffect extends ContinuousEffectImpl { - - UnboostCreaturesDefendingPlayerEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature); - staticText = "creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader"; - } - - private UnboostCreaturesDefendingPlayerEffect(final UnboostCreaturesDefendingPlayerEffect effect) { - super(effect); - } - - @Override - public UnboostCreaturesDefendingPlayerEffect copy() { - return new UnboostCreaturesDefendingPlayerEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (getAffectedObjectsSet()) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getTargetPointer().getFirst(game, source), game)) { - 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) { - int unboostCount = -1 * new CountersSourceCount(CounterType.P1P1).calculate(game, source, this); - permanent.addPower(unboostCount); - permanent.addToughness(unboostCount); - } else { - it.remove(); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java b/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java deleted file mode 100644 index 8659565dace..00000000000 --- a/Mage.Sets/src/mage/cards/d/DauntlessAvenger.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -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.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DauntlessAvenger 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 DauntlessAvenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setWhite(true); - this.nightCard = true; - - // Whenever Dauntless Avenger attacks, return target creature card with mana value 2 or less from your graveyard to the battlefield tapped and attacking. - Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true, true)); - ability.addTarget(new TargetCardInYourGraveyard(filter)); - this.addAbility(ability); - } - - private DauntlessAvenger(final DauntlessAvenger card) { - super(card); - } - - @Override - public DauntlessAvenger copy() { - return new DauntlessAvenger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java index 6d5c900626c..04275b5768e 100644 --- a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java +++ b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java @@ -31,9 +31,7 @@ public final class DavrielRogueShadowmage extends CardImpl { // 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 BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect( - 2, true, "them", "{this}" - ), false + new DamageTargetEffect(2).withTargetDescription("them"), false ).withInterveningIf(condition)); // -1: Target player discards a card. diff --git a/Mage.Sets/src/mage/cards/d/DayOfBlackSun.java b/Mage.Sets/src/mage/cards/d/DayOfBlackSun.java new file mode 100644 index 00000000000..8cbea998118 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DayOfBlackSun.java @@ -0,0 +1,56 @@ +package mage.cards.d; + +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +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.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DayOfBlackSun extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(DayOfBlackSunPredicate.instance); + } + + public DayOfBlackSun(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); + + // Each creature with mana value X or less loses all abilities until end of turn. Destroy those creatures. + this.getSpellAbility().addEffect(new LoseAllAbilitiesAllEffect(filter, Duration.EndOfTurn) + .setText("each creature with mana value X or less loses all abilities until end of turn")); + this.getSpellAbility().addEffect(new DestroyAllEffect(filter).setText("Destroy those creatures")); + } + + private DayOfBlackSun(final DayOfBlackSun card) { + super(card); + } + + @Override + public DayOfBlackSun copy() { + return new DayOfBlackSun(this); + } +} + +enum DayOfBlackSunPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getManaValue() <= GetXValue.instance.calculate(game, input.getSource(), null); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java index 7aa01edb49f..103813fc60f 100644 --- a/Mage.Sets/src/mage/cards/d/DaybreakRanger.java +++ b/Mage.Sets/src/mage/cards/d/DaybreakRanger.java @@ -1,46 +1,59 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author North */ -public final class DaybreakRanger extends CardImpl { +public final class DaybreakRanger extends TransformingDoubleFacedCard { public DaybreakRanger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ARCHER); - this.subtype.add(SubType.RANGER); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ARCHER, SubType.RANGER, SubType.WEREWOLF}, "{2}{G}", + "Nightfall Predator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.n.NightfallPredator.class; + // Daybreak Ranger + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - // {tap}: Daybreak Ranger deals 2 damage to target creature with flying. - Ability activatedAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - activatedAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_FLYING)); - this.addAbility(activatedAbility); + // {T}: Daybreak Ranger deals 2 damage to target creature with flying. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_FLYING)); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Daybreak Ranger. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Nightfall Predator + this.getRightHalfCard().setPT(4, 4); + + // {R}, {T}: Nightfall Predator fights target creature. + Ability ability2 = new SimpleActivatedAbility( + new FightTargetSourceEffect().setText("{this} fights target creature. (Each deals damage equal to its power to the other.)"), + new ManaCostsImpl<>("{R}") + ); + ability2.addCost(new TapSourceCost()); + ability2.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Nightfall Predator. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private DaybreakRanger(final DaybreakRanger card) { diff --git a/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java b/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java new file mode 100644 index 00000000000..beaa3eef13f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DazzlingTheaterPropRoom.java @@ -0,0 +1,52 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.effects.common.continuous.UntapAllDuringEachOtherPlayersUntapStepEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class DazzlingTheaterPropRoom extends RoomCard { + + private static final FilterNonlandCard filter = new FilterNonlandCard("creature spells you cast"); + + static { + filter.add(CardType.CREATURE.getPredicate()); + filter.add(Predicates.not(new AbilityPredicate(ConvokeAbility.class))); + } + + public DazzlingTheaterPropRoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{3}{W}", "{2}{W}"); + this.subtype.add(SubType.ROOM); + + // Dazzling Theater: Creature spells you cast have convoke. + Ability left = new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter)); + this.getLeftHalfCard().addAbility(left); + + // Prop Room: Untap each creature you control during each other player's untap step. + Ability right = new SimpleStaticAbility(new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES)); + this.getRightHalfCard().addAbility(right); + } + + private DazzlingTheaterPropRoom(final DazzlingTheaterPropRoom card) { + super(card); + } + + @Override + public DazzlingTheaterPropRoom copy() { + return new DazzlingTheaterPropRoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeadlyDancer.java b/Mage.Sets/src/mage/cards/d/DeadlyDancer.java deleted file mode 100644 index a294a3a26ec..00000000000 --- a/Mage.Sets/src/mage/cards/d/DeadlyDancer.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.mana.UntilEndOfTurnManaEffect; -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.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DeadlyDancer extends CardImpl { - - public DeadlyDancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // When this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end. - this.addAbility(new TransformIntoSourceTriggeredAbility(new UntilEndOfTurnManaEffect(Mana.RedMana(2)))); - - // {R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn. - Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( - 1, 0, Duration.EndOfTurn - ).setText("{this}"), new ManaCostsImpl<>("{R}{R}")); - ability.addEffect(new BoostTargetEffect(1, 0) - .setText("and another target creature each get +1/+0 until end of turn")); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); - this.addAbility(ability); - } - - private DeadlyDancer(final DeadlyDancer card) { - super(card); - } - - @Override - public DeadlyDancer copy() { - return new DeadlyDancer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeadlyPrecision.java b/Mage.Sets/src/mage/cards/d/DeadlyPrecision.java new file mode 100644 index 00000000000..e3ac37f7dc9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeadlyPrecision.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeadlyPrecision extends CardImpl { + + public DeadlyPrecision(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // As an additional cost to cast this spell, pay {4} or sacrifice an artifact or creature. + this.getSpellAbility().addCost(new OrCost( + "pay {4} or sacrifice an artifact or creature", new GenericManaCost(4), + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE) + )); + + // Destroy target creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private DeadlyPrecision(final DeadlyPrecision card) { + super(card); + } + + @Override + public DeadlyPrecision copy() { + return new DeadlyPrecision(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java b/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java deleted file mode 100644 index a796956ec84..00000000000 --- a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java +++ /dev/null @@ -1,93 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DeathbonnetHulk extends CardImpl { - - public DeathbonnetHulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.FUNGUS); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // At the beginning of your upkeep, you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on Deathbonnet Hulk. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DeathbonnetHulkEffect())); - } - - private DeathbonnetHulk(final DeathbonnetHulk card) { - super(card); - } - - @Override - public DeathbonnetHulk copy() { - return new DeathbonnetHulk(this); - } -} - -class DeathbonnetHulkEffect extends OneShotEffect { - - DeathbonnetHulkEffect() { - super(Outcome.Benefit); - staticText = "you may exile a card from a graveyard. " + - "If a creature card was exiled this way, put a +1/+1 counter on {this}"; - } - - private DeathbonnetHulkEffect(final DeathbonnetHulkEffect effect) { - super(effect); - } - - @Override - public DeathbonnetHulkEffect copy() { - return new DeathbonnetHulkEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCard target = new TargetCardInGraveyard(0, 1); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return false; - } - boolean flag = card.isCreature(game); - player.moveCards(card, Zone.EXILED, source, game); - if (!flag) { - return true; - } - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java b/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java index a5ed010d194..77ae57a0c44 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java +++ b/Mage.Sets/src/mage/cards/d/DeathbonnetSprout.java @@ -1,55 +1,66 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.TargetCard; +import mage.target.common.TargetCardInGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class DeathbonnetSprout extends CardImpl { +public final class DeathbonnetSprout extends TransformingDoubleFacedCard { - private static final Condition condition - = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); + private static final Condition condition = new CardsInControllerGraveyardCondition(3, StaticFilters.FILTER_CARD_CREATURE); private static final Hint hint = new ValueHint( "Creature cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE) ); public DeathbonnetSprout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS}, "{G}", + "Deathbonnet Hulk", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FUNGUS, SubType.HORROR}, "G"); - this.subtype.add(SubType.FUNGUS); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DeathbonnetHulk.class; + // Deathbonnet Sprout + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, mill a card. Then if there are three or more creature cards in your graveyard, transform Deathbonnet Sprout. - this.addAbility(new TransformAbility()); - Ability ability = new BeginningOfUpkeepTriggeredAbility( - new MillCardsControllerEffect(1) - ); - ability.addEffect(new ConditionalOneShotEffect( - new TransformSourceEffect(), condition, - "Then if there are three or more creature cards in your graveyard, transform {this}" - )); - this.addAbility(ability.addHint(hint)); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new MillCardsControllerEffect(1)); + ability.addEffect(new ConditionalOneShotEffect(new TransformSourceEffect(), condition, + "Then if there are three or more creature cards in your graveyard, transform {this}")); + this.getLeftHalfCard().addAbility(ability.addHint(hint)); + + + // Deathbonnet Hulk + this.getRightHalfCard().setPT(3, 3); + + + // At the beginning of your upkeep, you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on Deathbonnet Hulk. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new DeathbonnetHulkEffect())); } private DeathbonnetSprout(final DeathbonnetSprout card) { @@ -61,3 +72,44 @@ public final class DeathbonnetSprout extends CardImpl { return new DeathbonnetSprout(this); } } + +class DeathbonnetHulkEffect extends OneShotEffect { + DeathbonnetHulkEffect() { + super(Outcome.Benefit); + staticText = "you may exile a card from a graveyard. If a creature card was exiled this way, put a +1/+1 counter on {this}"; + } + + private DeathbonnetHulkEffect(final DeathbonnetHulkEffect effect) { + super(effect); + } + + @Override + public DeathbonnetHulkEffect copy() { + return new DeathbonnetHulkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInGraveyard(0, 1); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + boolean creature = card.isCreature(game); + player.moveCards(card, Zone.EXILED, source, game); + if (!creature) { + return true; + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeemInferior.java b/Mage.Sets/src/mage/cards/d/DeemInferior.java index 2745bc88338..dc4a84da763 100644 --- a/Mage.Sets/src/mage/cards/d/DeemInferior.java +++ b/Mage.Sets/src/mage/cards/d/DeemInferior.java @@ -3,16 +3,12 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -33,7 +29,7 @@ public final class DeemInferior extends CardImpl { this.addAbility(ability.addHint(CardsDrawnThisTurnDynamicValue.getHint())); // The owner of target nonland permanent puts it into their library second from the top or on the bottom. - this.getSpellAbility().addEffect(new DeemInferiorEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } @@ -46,40 +42,3 @@ public final class DeemInferior extends CardImpl { return new DeemInferior(this); } } - -// Same as Temporal Cleansing. -class DeemInferiorEffect extends OneShotEffect { - - DeemInferiorEffect() { - super(Outcome.Benefit); - staticText = "the owner of target nonland permanent puts it into their library second from the top or on the bottom"; - } - - private DeemInferiorEffect(final DeemInferiorEffect effect) { - super(effect); - } - - @Override - public DeemInferiorEffect copy() { - return new DeemInferiorEffect(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; - } - if (player.chooseUse( - outcome, "Put " + permanent.getIdName() + " second from the top or on the bottom?", - null, "Second from top", "Bottom", source, game - )) { - return player.putCardOnTopXOfLibrary(permanent, game, source, 2, true); - } - return player.putCardsOnBottomOfLibrary(permanent, game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeerDog.java b/Mage.Sets/src/mage/cards/d/DeerDog.java new file mode 100644 index 00000000000..45518297a9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeerDog.java @@ -0,0 +1,37 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.keyword.FirstStrikeAbility; +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 DeerDog extends CardImpl { + + public DeerDog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.ELK); + this.subtype.add(SubType.DOG); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + } + + private DeerDog(final DeerDog card) { + super(card); + } + + @Override + public DeerDog copy() { + return new DeerDog(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DefiantThundermaw.java b/Mage.Sets/src/mage/cards/d/DefiantThundermaw.java deleted file mode 100644 index 79190ed8b56..00000000000 --- a/Mage.Sets/src/mage/cards/d/DefiantThundermaw.java +++ /dev/null @@ -1,90 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -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.Outcome; -import mage.constants.SubType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DefiantThundermaw extends CardImpl { - - private static final FilterControlledCreaturePermanent filter - = new FilterControlledCreaturePermanent(SubType.DRAGON); - - public DefiantThundermaw(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever a Dragon you control attacks, it deals 2 damage to any target. - Ability ability = new AttacksCreatureYouControlTriggeredAbility( - new DefiantThundermawEffect(), false, filter - ); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - } - - private DefiantThundermaw(final DefiantThundermaw card) { - super(card); - } - - @Override - public DefiantThundermaw copy() { - return new DefiantThundermaw(this); - } -} - -class DefiantThundermawEffect extends OneShotEffect { - - DefiantThundermawEffect() { - super(Outcome.Benefit); - staticText = "it deals 2 damage to any target"; - } - - private DefiantThundermawEffect(final DefiantThundermawEffect effect) { - super(effect); - } - - @Override - public DefiantThundermawEffect copy() { - return new DefiantThundermawEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - MageObjectReference mor = (MageObjectReference) getValue("attackerRef"); - if (mor == null) { - return false; - } - game.damagePlayerOrPermanent( - getTargetPointer().getFirst(game, source), 2, - mor.getSourceId(), source, game, false, true - ); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DefiledCryptCadaverLab.java b/Mage.Sets/src/mage/cards/d/DefiledCryptCadaverLab.java new file mode 100644 index 00000000000..3029cc0fd6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DefiledCryptCadaverLab.java @@ -0,0 +1,45 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.CardsLeaveGraveyardTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.filter.StaticFilters; +import mage.game.permanent.token.HorrorEnchantmentCreatureToken; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DefiledCryptCadaverLab extends RoomCard { + + public DefiledCryptCadaverLab(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{3}{B}", "{B}"); + + // Defiled Crypt + // Whenever one or more cards leave your graveyard, create a 2/2 black Horror enchantment creature token. This ability triggers only once each turn. + this.getLeftHalfCard().addAbility(new CardsLeaveGraveyardTriggeredAbility( + new CreateTokenEffect(new HorrorEnchantmentCreatureToken()) + ).setTriggersLimitEachTurn(1)); + + // Cadaver Lab + // When you unlock this door, return target creature card from your graveyard to your hand. + Ability ability = new UnlockThisDoorTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false, false); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(ability); + } + + private DefiledCryptCadaverLab(final DefiledCryptCadaverLab card) { + super(card); + } + + @Override + public DefiledCryptCadaverLab copy() { + return new DefiledCryptCadaverLab(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DelugeOfTheDead.java b/Mage.Sets/src/mage/cards/d/DelugeOfTheDead.java deleted file mode 100644 index a8c1e8478aa..00000000000 --- a/Mage.Sets/src/mage/cards/d/DelugeOfTheDead.java +++ /dev/null @@ -1,82 +0,0 @@ -package mage.cards.d; - -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -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.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.token.ZombieToken; -import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DelugeOfTheDead extends CardImpl { - - public DelugeOfTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setBlack(true); - this.nightCard = true; - - // When Deluge of the Dead enters the battlefield, create two 2/2 black Zombie creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 2))); - - // {2}{B}: Exile target card from a graveyard. If it was a creature card, create a 2/2 black Zombie creature token. - Ability ability = new SimpleActivatedAbility(new DelugeOfTheDeadEffect(), new ManaCostsImpl<>("{2}{B}")); - ability.addTarget(new TargetCardInGraveyard()); - this.addAbility(ability); - } - - private DelugeOfTheDead(final DelugeOfTheDead card) { - super(card); - } - - @Override - public DelugeOfTheDead copy() { - return new DelugeOfTheDead(this); - } -} - -class DelugeOfTheDeadEffect extends OneShotEffect { - - DelugeOfTheDeadEffect() { - super(Outcome.Benefit); - staticText = "exile target card from a graveyard. " + - "If it was a creature card, create a 2/2 black Zombie creature token"; - } - - private DelugeOfTheDeadEffect(final DelugeOfTheDeadEffect effect) { - super(effect); - } - - @Override - public DelugeOfTheDeadEffect copy() { - return new DelugeOfTheDeadEffect(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 (card.isCreature(game)) { - new ZombieToken().putOntoBattlefield(1, game, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java index 0b89a031e26..1006315827d 100644 --- a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java +++ b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java @@ -1,9 +1,8 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.*; import mage.constants.CardType; @@ -19,21 +18,25 @@ import java.util.UUID; /** * @author Alvin */ -public final class DelverOfSecrets extends CardImpl { +public final class DelverOfSecrets extends TransformingDoubleFacedCard { public DelverOfSecrets(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{U}", + "Insectile Aberration", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.INSECT}, "U"); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.i.InsectileAberration.class; + // Delver of Secrets + this.getLeftHalfCard().setPT(1, 1); // At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DelverOfSecretsEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new DelverOfSecretsEffect())); + + // Insectile Aberration + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private DelverOfSecrets(final DelverOfSecrets card) { @@ -47,10 +50,9 @@ public final class DelverOfSecrets extends CardImpl { } class DelverOfSecretsEffect extends OneShotEffect { - - public DelverOfSecretsEffect() { + DelverOfSecretsEffect() { super(Outcome.Benefit); - this.staticText = "look at the top card of your library. You may reveal that card. " + + staticText = "look at the top card of your library. You may reveal that card. " + "If an instant or sorcery card is revealed this way, transform {this}"; } diff --git a/Mage.Sets/src/mage/cards/d/DemonPossessedWitch.java b/Mage.Sets/src/mage/cards/d/DemonPossessedWitch.java deleted file mode 100644 index ddfbb76f007..00000000000 --- a/Mage.Sets/src/mage/cards/d/DemonPossessedWitch.java +++ /dev/null @@ -1,46 +0,0 @@ - -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.DestroyTargetEffect; -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 fireshoes - */ -public final class DemonPossessedWitch extends CardImpl { - - public DemonPossessedWitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // When this creature transforms into Demon-Possessed Witch, you may destroy target creature. - Ability ability = new TransformIntoSourceTriggeredAbility(new DestroyTargetEffect(), true); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); - } - - private DemonPossessedWitch(final DemonPossessedWitch card) { - super(card); - } - - @Override - public DemonPossessedWitch copy() { - return new DemonPossessedWitch(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/Demonfire.java b/Mage.Sets/src/mage/cards/d/Demonfire.java index fc9191b441c..d140c247695 100644 --- a/Mage.Sets/src/mage/cards/d/Demonfire.java +++ b/Mage.Sets/src/mage/cards/d/Demonfire.java @@ -41,7 +41,7 @@ public final class Demonfire extends CardImpl { // Hellbent - If you have no cards in hand, Demonfire can't be countered and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(GetXValue.instance, false), + new DamageTargetEffect(GetXValue.instance).withCantBePrevented(), HellbentCondition.instance, "
Hellbent — If you have no cards in hand, this spell can't be countered and the damage can't be prevented.")); // can't be countered diff --git a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java index 55885247a4a..9d6652c5e49 100644 --- a/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java +++ b/Mage.Sets/src/mage/cards/d/DennickPiousApprentice.java @@ -1,44 +1,58 @@ package mage.cards.d; -import mage.MageInt; +import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CantBeTargetedCardsGraveyardsEffect; +import mage.abilities.effects.keyword.InvestigateEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.TargetController; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author LePwnerer */ -public final class DennickPiousApprentice extends CardImpl { +public final class DennickPiousApprentice extends TransformingDoubleFacedCard { public DennickPiousApprentice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{W}{U}", + "Dennick, Pious Apparition", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "WU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.d.DennickPiousApparition.class; + // Dennick, Pious Apprentice + this.getLeftHalfCard().setPT(2, 3); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Cards in graveyards can't be the targets of spells or abilities. - this.addAbility(new SimpleStaticAbility(new CantBeTargetedCardsGraveyardsEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CantBeTargetedCardsGraveyardsEffect())); // Disturb {2}{W}{U} - this.addAbility(new DisturbAbility(this, "{2}{W}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{W}{U}")); + // Dennick, Pious Apparition + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever one or more creature cards are put into graveyards from anywhere, investigate. This ability triggers only once each turn. + this.getRightHalfCard().addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + new InvestigateEffect(1), false, StaticFilters.FILTER_CARD_CREATURE, TargetController.ANY + ).setTriggersLimitEachTurn(1).setTriggerPhrase("Whenever one or more creature cards are put into graveyards from anywhere, ")); + + // If Dennick, Pious Apparition would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DennickPiousApprentice(final DennickPiousApprentice card) { diff --git a/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java b/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java deleted file mode 100644 index 2503f1601ba..00000000000 --- a/Mage.Sets/src/mage/cards/d/DepartedSoulkeeper.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.common.CanBlockOnlyFlyingAbility; -import mage.abilities.keyword.DisturbAbility; -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 DepartedSoulkeeper extends CardImpl { - - public DepartedSoulkeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Departed Soulkeeper can block only creatures with flying. - this.addAbility(new CanBlockOnlyFlyingAbility()); - - // If Departed Soulkeeper would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DepartedSoulkeeper(final DepartedSoulkeeper card) { - super(card); - } - - @Override - public DepartedSoulkeeper copy() { - return new DepartedSoulkeeper(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DepravedHarvester.java b/Mage.Sets/src/mage/cards/d/DepravedHarvester.java deleted file mode 100644 index 8a385930f39..00000000000 --- a/Mage.Sets/src/mage/cards/d/DepravedHarvester.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -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 DepravedHarvester extends CardImpl { - - public DepravedHarvester(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private DepravedHarvester(final DepravedHarvester card) { - super(card); - } - - @Override - public DepravedHarvester copy() { - return new DepravedHarvester(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DerelictAtticWidowsWalk.java b/Mage.Sets/src/mage/cards/d/DerelictAtticWidowsWalk.java new file mode 100644 index 00000000000..969eb49623f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DerelictAtticWidowsWalk.java @@ -0,0 +1,52 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DerelictAtticWidowsWalk extends RoomCard { + + public DerelictAtticWidowsWalk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{B}", "{3}{B}"); + + // Derelict Attic + // When you unlock this door, you draw two cards and you lose 2 life. + Ability ability = new UnlockThisDoorTriggeredAbility( + new DrawCardSourceControllerEffect(2, true), false, true + ); + ability.addEffect(new LoseLifeSourceControllerEffect(2).concatBy("and")); + this.getLeftHalfCard().addAbility(ability); + + // Widow's Walk + // Whenever a creature you control attacks alone, it gets +1/+0 and gains deathtouch until end of turn. + ability = new AttacksAloneControlledTriggeredAbility( + new BoostTargetEffect(1, 0).setText("it gets +1/+0"), + StaticFilters.FILTER_CONTROLLED_A_CREATURE, true, false + ); + ability.addEffect(new GainAbilityTargetEffect(DeathtouchAbility.getInstance()) + .setText("and gains deathtouch until end of turn")); + this.getRightHalfCard().addAbility(ability); + } + + private DerelictAtticWidowsWalk(final DerelictAtticWidowsWalk card) { + super(card); + } + + @Override + public DerelictAtticWidowsWalk copy() { + return new DerelictAtticWidowsWalk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DesperateFarmer.java b/Mage.Sets/src/mage/cards/d/DesperateFarmer.java index a0aae4476de..0a111e8b0b9 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateFarmer.java +++ b/Mage.Sets/src/mage/cards/d/DesperateFarmer.java @@ -1,12 +1,10 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -16,26 +14,30 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DesperateFarmer extends CardImpl { +public final class DesperateFarmer extends TransformingDoubleFacedCard { public DesperateFarmer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{2}{B}", + "Depraved Harvester", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "B"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.d.DepravedHarvester.class; + // Desperate Farmer + this.getLeftHalfCard().setPT(2, 2); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // When another creature you control dies, transform Desperate Farmer. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility( - new TransformSourceEffect(), false, - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( + new TransformSourceEffect(), false, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE ).setTriggerPhrase("When another creature you control dies, ")); + + // Depraved Harvester + this.getRightHalfCard().setPT(4, 3); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); } private DesperateFarmer(final DesperateFarmer card) { diff --git a/Mage.Sets/src/mage/cards/d/DesperateGambit.java b/Mage.Sets/src/mage/cards/d/DesperateGambit.java index d51e7d978d6..53084581d5f 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateGambit.java +++ b/Mage.Sets/src/mage/cards/d/DesperateGambit.java @@ -110,12 +110,10 @@ class DesperateGambitEffect extends PreventionEffectImpl { if (super.applies(event, source, game) && event instanceof DamageEvent && event.getAmount() > 0) { if (wonFlip) { event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2)); - this.discard(); } else { preventDamageAction(event, source, game); - this.discard(); - return true; } + this.discard(); } } return false; diff --git a/Mage.Sets/src/mage/cards/d/DesperatePlea.java b/Mage.Sets/src/mage/cards/d/DesperatePlea.java new file mode 100644 index 00000000000..9b826a29846 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DesperatePlea.java @@ -0,0 +1,84 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesPower; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +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.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DesperatePlea extends CardImpl { + + public DesperatePlea(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, sacrifice a creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); + + // Choose one or both -- + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // * Return target creature card from your graveyard to the battlefield if its power is less than or equal to the sacrificed creature's power. + this.getSpellAbility().addEffect(new DesperatePleaEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // * Destroy target creature. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetCreaturePermanent())); + } + + private DesperatePlea(final DesperatePlea card) { + super(card); + } + + @Override + public DesperatePlea copy() { + return new DesperatePlea(this); + } +} + +class DesperatePleaEffect extends OneShotEffect { + + DesperatePleaEffect() { + super(Outcome.Benefit); + staticText = "return target creature card from your graveyard to the battlefield " + + "if its power is less than or equal to the sacrificed creature's power"; + } + + private DesperatePleaEffect(final DesperatePleaEffect effect) { + super(effect); + } + + @Override + public DesperatePleaEffect copy() { + return new DesperatePleaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + return player != null && card != null + && card.getPower().getValue() <= SacrificeCostCreaturesPower.instance.calculate(game, source, this) + && player.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DestinedConfrontation.java b/Mage.Sets/src/mage/cards/d/DestinedConfrontation.java new file mode 100644 index 00000000000..2bf1bb8d80d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DestinedConfrontation.java @@ -0,0 +1,122 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.MageObject; +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.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DestinedConfrontation extends CardImpl { + + public DestinedConfrontation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); + + // Each player chooses any number of creatures they control with total power 4 or less, then sacrifices all other creatures they control. + this.getSpellAbility().addEffect(new DestinedConfrontationEffect()); + } + + private DestinedConfrontation(final DestinedConfrontation card) { + super(card); + } + + @Override + public DestinedConfrontation copy() { + return new DestinedConfrontation(this); + } +} + +class DestinedConfrontationEffect extends OneShotEffect { + + DestinedConfrontationEffect() { + super(Outcome.Benefit); + staticText = "each player chooses any number of creatures they control " + + "with total power 4 or less, then sacrifices all other creatures they control"; + } + + private DestinedConfrontationEffect(final DestinedConfrontationEffect effect) { + super(effect); + } + + @Override + public DestinedConfrontationEffect copy() { + return new DestinedConfrontationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set permanents = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + TargetPermanent target = new DestinedConfrontationTarget(); + player.choose(outcome, target, source, game); + permanents.addAll(target.getTargets()); + } + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source, game + )) { + if (!permanents.contains(permanent.getId())) { + permanent.sacrifice(source, game); + } + } + return true; + } +} + +class DestinedConfrontationTarget extends TargetPermanent { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creatures you control with total power 4 or less"); + + DestinedConfrontationTarget() { + super(0, Integer.MAX_VALUE, filter, true); + } + + private DestinedConfrontationTarget(final DestinedConfrontationTarget target) { + super(target); + } + + @Override + public DestinedConfrontationTarget copy() { + return new DestinedConfrontationTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(id); + if (permanent == null) { + return false; + } + return this + .getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum() + permanent.getPower().getValue() <= 4; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DevastatingOnslaught.java b/Mage.Sets/src/mage/cards/d/DevastatingOnslaught.java index 363a739303f..e3bdc8003ee 100644 --- a/Mage.Sets/src/mage/cards/d/DevastatingOnslaught.java +++ b/Mage.Sets/src/mage/cards/d/DevastatingOnslaught.java @@ -62,8 +62,7 @@ class DevastatingOnslaughtEffect extends OneShotEffect { if (permanent == null || xValue < 1) { return false; } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); - effect.setHasHaste(true); + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true, xValue); effect.setSavedPermanent(permanent); effect.apply(game, source); effect.sacrificeTokensCreatedAtNextEndStep(game, source); diff --git a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java index e16068a08a7..76e8fdac5f8 100644 --- a/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java +++ b/Mage.Sets/src/mage/cards/d/DevotedGrafkeeper.java @@ -1,14 +1,15 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.CanBlockOnlyFlyingAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SetTargetPointer; import mage.constants.SubType; @@ -21,19 +22,19 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DevotedGrafkeeper extends CardImpl { +public final class DevotedGrafkeeper extends TransformingDoubleFacedCard { public DevotedGrafkeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{W}{U}", + "Departed Soulkeeper", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "WU"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.d.DepartedSoulkeeper.class; + // Devoted Grafkeeper + this.getLeftHalfCard().setPT(2, 1); // When Devoted Grafkeeper enters the battlefield, mill two cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); // Whenever you cast a spell from your graveyard, tap target creature you don't control. Ability ability = new SpellCastControllerTriggeredAbility( @@ -41,10 +42,22 @@ public final class DevotedGrafkeeper extends CardImpl { false, SetTargetPointer.NONE, Zone.GRAVEYARD ); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {1}{W}{U} - this.addAbility(new DisturbAbility(this, "{1}{W}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}{U}")); + + // Departed Soulkeeper + this.getRightHalfCard().setPT(3, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Departed Soulkeeper can block only creatures with flying. + this.getRightHalfCard().addAbility(new CanBlockOnlyFlyingAbility()); + + // If Departed Soulkeeper would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DevotedGrafkeeper(final DevotedGrafkeeper card) { diff --git a/Mage.Sets/src/mage/cards/d/DiligentZookeeper.java b/Mage.Sets/src/mage/cards/d/DiligentZookeeper.java new file mode 100644 index 00000000000..22ebabc3773 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiligentZookeeper.java @@ -0,0 +1,91 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DiligentZookeeper extends CardImpl { + + public DiligentZookeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Each non-Human creature you control gets +1/+1 for each of its creature types, to a maximum of 10. + this.addAbility(new SimpleStaticAbility(new DiligentZookeeperEffect())); + } + + private DiligentZookeeper(final DiligentZookeeper card) { + super(card); + } + + @Override + public DiligentZookeeper copy() { + return new DiligentZookeeper(this); + } +} + +class DiligentZookeeperEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(Predicates.not(SubType.HUMAN.getPredicate())); + } + + DiligentZookeeperEffect() { + super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); + staticText = "each non-Human creature you control gets +1/+1 for each of its creature types, to a maximum of 10"; + } + + private DiligentZookeeperEffect(final DiligentZookeeperEffect effect) { + super(effect); + } + + @Override + public DiligentZookeeperEffect copy() { + return new DiligentZookeeperEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (permanent.isAllCreatureTypes(game)) { + permanent.addPower(10); + permanent.addToughness(10); + continue; + } + int types = Math.min( + 10, permanent + .getSubtype(game) + .stream() + .map(SubType::getSubTypeSet) + .filter(SubTypeSet.CreatureType::equals) + .mapToInt(x -> 1) + .sum() + ); + permanent.addPower(types); + permanent.addToughness(types); + continue; + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java index 1916be7d1ce..1026ddb5fe7 100644 --- a/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java +++ b/Mage.Sets/src/mage/cards/d/DionBahamutsDominant.java @@ -1,45 +1,48 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.permanent.token.WaylayToken; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DionBahamutsDominant extends CardImpl { +public final class DionBahamutsDominant extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterPermanent(SubType.KNIGHT, ""); public DionBahamutsDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.KNIGHT}, "{3}{W}", + "Bahamut, Warden of Light", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.DRAGON}, "W"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BahamutWardenOfLight.class; + // Dion, Bahamut's Dominant + this.getLeftHalfCard().setPT(3, 3); // Dragonfire Dive -- During your turn, Dion and other Knights you control have flying. Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( @@ -50,18 +53,47 @@ public final class DionBahamutsDominant extends CardImpl { new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter), MyTurnCondition.instance, "and other Knights you control have flying" )); - this.addAbility(ability.withFlavorWord("Dragonfire Dive")); + this.getLeftHalfCard().addAbility(ability.withFlavorWord("Dragonfire Dive")); // When Dion enters, create a 2/2 white Knight creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WaylayToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WaylayToken()))); // {4}{W}{W}, {T}: Exile Dion, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - ability = new ActivateAsSorceryActivatedAbility( + Ability ability2 = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{W}{W}") ); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); + ability2.addCost(new TapSourceCost()); + this.getLeftHalfCard().addAbility(ability2); + + // Bahamut, Warden of Light + this.getRightHalfCard().setPT(5, 5); + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I, II -- Wings of Light -- Put a +1/+1 counter on each other creature you control. Those creatures gain flying until end of turn. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability3 -> { + ability3.addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE + )); + ability3.addEffect(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("Those creatures gain flying until end of turn")); + ability3.withFlavorWord("Wings of Light"); + }); + + // III -- Gigaflare -- Destroy target permanent. Exile Bahamut, then return it to the battlefield. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, ability4 -> { + ability4.addEffect(new DestroyTargetEffect()); + ability4.addEffect(new ExileSourceAndReturnFaceUpEffect()); + ability4.addTarget(new TargetPermanent()); + ability4.withFlavorWord("Gigaflare"); + }); + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private DionBahamutsDominant(final DionBahamutsDominant card) { diff --git a/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java b/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java deleted file mode 100644 index 3088dada74a..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireBlunderbuss.java +++ /dev/null @@ -1,170 +0,0 @@ -package mage.cards.d; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.SacrificeCost; -import mage.abilities.costs.UseAttachedCost; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.DamageWithPowerFromSourceToAnotherTargetEffect; -import mage.abilities.effects.common.DoWhenCostPaid; -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.filter.common.FilterControlledArtifactPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.MageObjectReferencePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class DireBlunderbuss extends CardImpl { - - public DireBlunderbuss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - - this.subtype.add(SubType.EQUIPMENT); - this.color.setRed(true); - - // Equipped creature gets +3/+0 and has "Whenever this creature attacks, you may sacrifice an artifact other than Dire Blunderbuss. When you do, this creature deals damage equal to its power to target creature" - Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); - ability.addEffect(new DireBlunderbussGainAbilityEffect()); - this.addAbility(ability); - - // Equip {1} - this.addAbility(new EquipAbility(1, false)); - } - - private DireBlunderbuss(final DireBlunderbuss card) { - super(card); - } - - @Override - public DireBlunderbuss copy() { - return new DireBlunderbuss(this); - } -} - -class DireBlunderbussGainAbilityEffect extends ContinuousEffectImpl { - - DireBlunderbussGainAbilityEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "and has \"Whenever this creature attacks, you may sacrifice an artifact other than {this}. " - + "When you do, this creature deals damage equal to its power to target creature.\""; - } - - protected DireBlunderbussGainAbilityEffect(final DireBlunderbussGainAbilityEffect effect) { - super(effect); - } - - @Override - public DireBlunderbussGainAbilityEffect copy() { - return new DireBlunderbussGainAbilityEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (getAffectedObjectsSet()) { - Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo()))); - } - } - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = null; - if (getAffectedObjectsSet()) { - permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - discard(); - return true; - } - } else { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - permanent = game.getPermanentOrLKIBattlefield(equipment.getAttachedTo()); - } - } - if (permanent == null) { - return true; - } - Ability ability = makeAbility(game, source); - ability.getEffects().setValue("attachedPermanent", game.getPermanent(source.getSourceId())); - permanent.addAbility(ability, source.getSourceId(), game); - return true; - } - - protected Ability makeAbility(Game game, Ability source) { - ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( - new DamageWithPowerFromSourceToAnotherTargetEffect("this creature"), false - ); - reflexive.addTarget(new TargetCreaturePermanent()); - return new AttacksTriggeredAbility( - new DoWhenCostPaid( - reflexive, new DireBlunderbussSacrificeCost(source, game), - "Sacrifice an artifact other than the equipment?" - ), false - ); - } -} - -class DireBlunderbussSacrificeCost extends UseAttachedCost implements SacrificeCost { - - private final SacrificeTargetCost sacrificeCost; - - DireBlunderbussSacrificeCost(Ability source, Game game) { - super(); - this.setMageObjectReference(source, game); - FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); - filter.add(Predicates.not(new MageObjectReferencePredicate(this.mageObjectReference))); - this.sacrificeCost = new SacrificeTargetCost(filter); - } - - private DireBlunderbussSacrificeCost(final DireBlunderbussSacrificeCost cost) { - super(cost); - this.sacrificeCost = cost.sacrificeCost.copy(); - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return sacrificeCost.canPay(ability, source, controllerId, game); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (mageObjectReference == null) { - return false; - } - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - return paid; - } - paid = sacrificeCost.pay(ability, game, source, controllerId, noMana, costToPay); - return paid; - } - - @Override - public DireBlunderbussSacrificeCost copy() { - return new DireBlunderbussSacrificeCost(this); - } - - @Override - public String getText() { - return "sacrifice an artifact other than " + this.name; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DireFlail.java b/Mage.Sets/src/mage/cards/d/DireFlail.java index 2224c630043..d4e1ab257c1 100644 --- a/Mage.Sets/src/mage/cards/d/DireFlail.java +++ b/Mage.Sets/src/mage/cards/d/DireFlail.java @@ -1,35 +1,62 @@ package mage.cards.d; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.SacrificeCost; +import mage.abilities.costs.UseAttachedCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DamageWithPowerFromSourceToAnotherTargetEffect; +import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.keyword.EquipAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author Susucr */ -public final class DireFlail extends CardImpl { +public final class DireFlail extends TransformingDoubleFacedCard { public DireFlail(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{R}"); - this.secondSideCardClazz = mage.cards.d.DireBlunderbuss.class; - - this.subtype.add(SubType.EQUIPMENT); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{R}", + "Dire Blunderbuss", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "R"); + // Dire Flail // Equipped creature gets +2/+0. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); // Equip {1} - this.addAbility(new EquipAbility(1, false)); + this.getLeftHalfCard().addAbility(new EquipAbility(1, false)); // Craft with artifact {3}{R}{R} - this.addAbility(new CraftAbility("{3}{R}{R}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{R}{R}")); + + // Dire Blunderbuss + + // Equipped creature gets +3/+0 and has "Whenever this creature attacks, you may sacrifice an artifact other than Dire Blunderbuss. When you do, this creature deals damage equal to its power to target creature" + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 0)); + ability.addEffect(new DireBlunderbussGainAbilityEffect()); + this.getRightHalfCard().addAbility(ability); + + // Equip {1} + this.getRightHalfCard().addAbility(new EquipAbility(1, false)); } private DireFlail(final DireFlail card) { @@ -41,3 +68,109 @@ public final class DireFlail extends CardImpl { return new DireFlail(this); } } + +class DireBlunderbussGainAbilityEffect extends ContinuousEffectImpl { + + DireBlunderbussGainAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "and has \"Whenever this creature attacks, you may sacrifice an artifact other than {this}. " + + "When you do, this creature deals damage equal to its power to target creature.\""; + } + + protected DireBlunderbussGainAbilityEffect(final DireBlunderbussGainAbilityEffect effect) { + super(effect); + } + + @Override + public DireBlunderbussGainAbilityEffect copy() { + return new DireBlunderbussGainAbilityEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (getAffectedObjectsSet()) { + Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo()))); + } + } + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = null; + if (getAffectedObjectsSet()) { + permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return true; + } + } else { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment != null && equipment.getAttachedTo() != null) { + permanent = game.getPermanentOrLKIBattlefield(equipment.getAttachedTo()); + } + } + if (permanent == null) { + return true; + } + ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility( + new DamageWithPowerFromSourceToAnotherTargetEffect("this creature"), false + ); + reflexive.addTarget(new TargetCreaturePermanent()); + Ability grant = new AttacksTriggeredAbility( + new DoWhenCostPaid( + reflexive, new DireBlunderbussSacrificeCost(source, game), + "Sacrifice an artifact other than the equipment?" + ), false + ); + permanent.addAbility(grant, source.getSourceId(), game); + return true; + } +} + +class DireBlunderbussSacrificeCost extends UseAttachedCost implements SacrificeCost { + + private final SacrificeTargetCost sacrificeCost; + private final mage.MageObjectReference mageObjectReference; + + DireBlunderbussSacrificeCost(Ability source, Game game) { + super(); + this.mageObjectReference = new mage.MageObjectReference(source.getSourceObject(game), game); + FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); + filter.add(Predicates.not(new MageObjectReferencePredicate(this.mageObjectReference))); + this.sacrificeCost = new SacrificeTargetCost(filter); + } + + private DireBlunderbussSacrificeCost(final DireBlunderbussSacrificeCost cost) { + super(cost); + this.sacrificeCost = cost.sacrificeCost.copy(); + this.mageObjectReference = cost.mageObjectReference; + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return sacrificeCost.canPay(ability, source, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Permanent equipment = game.getPermanent(source.getSourceId()); + if (equipment == null) { + return paid; + } + paid = sacrificeCost.pay(ability, game, source, controllerId, noMana, costToPay); + return paid; + } + + @Override + public DireBlunderbussSacrificeCost copy() { + return new DireBlunderbussSacrificeCost(this); + } + + @Override + public String getText() { + return "sacrifice an artifact other than " + this.name; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DireStrainAnarchist.java b/Mage.Sets/src/mage/cards/d/DireStrainAnarchist.java deleted file mode 100644 index a683736bce5..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireStrainAnarchist.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetPlaneswalkerPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DireStrainAnarchist extends CardImpl { - - public DireStrainAnarchist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Whenever Dire-Strain Anarchist attacks, it deals 2 damage to each of up to one target creature, up to one target player, and/or up to one target planeswalker. - Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(2).setText("it deals 2 damage to each of up to one target creature, up to one target player, and/or up to one target planeswalker")); - ability.addTarget(new TargetCreaturePermanent(0, 1)); - ability.addTarget(new TargetPlayer(0, 1, false)); - ability.addTarget(new TargetPlaneswalkerPermanent(0, 1)); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private DireStrainAnarchist(final DireStrainAnarchist card) { - super(card); - } - - @Override - public DireStrainAnarchist copy() { - return new DireStrainAnarchist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DireStrainBrawler.java b/Mage.Sets/src/mage/cards/d/DireStrainBrawler.java deleted file mode 100644 index b1ee9f52960..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireStrainBrawler.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -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 DireStrainBrawler extends CardImpl { - - public DireStrainBrawler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setGreen(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private DireStrainBrawler(final DireStrainBrawler card) { - super(card); - } - - @Override - public DireStrainBrawler copy() { - return new DireStrainBrawler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java b/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java deleted file mode 100644 index abb57f23514..00000000000 --- a/Mage.Sets/src/mage/cards/d/DireStrainDemolisher.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.WardAbility; -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 DireStrainDemolisher extends CardImpl { - - public DireStrainDemolisher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(8); - this.toughness = new MageInt(7); - this.color.setGreen(true); - this.nightCard = true; - - // Ward {3} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{3}"))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private DireStrainDemolisher(final DireStrainDemolisher card) { - super(card); - } - - @Override - public DireStrainDemolisher copy() { - return new DireStrainDemolisher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DisciplesOfTheInferno.java b/Mage.Sets/src/mage/cards/d/DisciplesOfTheInferno.java deleted file mode 100644 index 8344681452f..00000000000 --- a/Mage.Sets/src/mage/cards/d/DisciplesOfTheInferno.java +++ /dev/null @@ -1,113 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.keyword.ProwessAbility; -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.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DisciplesOfTheInferno extends CardImpl { - - public DisciplesOfTheInferno(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MONK); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Prowess - this.addAbility(new ProwessAbility()); - - // If a noncreature source you control would deal damage to a creature, battle, or opponent, it deals that much damage plus 2 instead. - this.addAbility(new SimpleStaticAbility(new DisciplesOfTheInfernoEffect())); - } - - private DisciplesOfTheInferno(final DisciplesOfTheInferno card) { - super(card); - } - - @Override - public DisciplesOfTheInferno copy() { - return new DisciplesOfTheInferno(this); - } -} - -class DisciplesOfTheInfernoEffect extends ReplacementEffectImpl { - - DisciplesOfTheInfernoEffect() { - super(Duration.WhileOnBattlefield, Outcome.Damage); - this.staticText = "if a noncreature source you control would deal damage " + - "to a creature, battle, or opponent, it deals that much damage plus 2 instead"; - } - - private DisciplesOfTheInfernoEffect(final DisciplesOfTheInfernoEffect effect) { - super(effect); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(CardUtil.overflowInc(event.getAmount(), 2)); - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - switch (event.getType()) { - case DAMAGE_PERMANENT: - case DAMAGE_PLAYER: - return true; - } - return false; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null || !controller.hasOpponent(event.getTargetId(), game) - && Optional - .of(event.getTargetId()) - .map(game::getPermanent) - .filter(Objects::nonNull) - .map(permanent -> !permanent.isCreature(game) && !permanent.isBattle(game)) - .orElse(true)) { - return false; - } - MageObject sourceObject; - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); - if (sourcePermanent == null) { - sourceObject = game.getObject(event.getSourceId()); - } else { - sourceObject = sourcePermanent; - } - return sourceObject != null - && !sourceObject.isCreature(game) - && event.getAmount() > 0; - } - - @Override - public DisciplesOfTheInfernoEffect copy() { - return new DisciplesOfTheInfernoEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DistractingGeist.java b/Mage.Sets/src/mage/cards/d/DistractingGeist.java index 6d46c46ca82..9abe93864d9 100644 --- a/Mage.Sets/src/mage/cards/d/DistractingGeist.java +++ b/Mage.Sets/src/mage/cards/d/DistractingGeist.java @@ -1,49 +1,72 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.AttachmentType; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DistractingGeist extends CardImpl { +public final class DistractingGeist extends TransformingDoubleFacedCard { - private static final FilterPermanent filter - = new FilterCreaturePermanent("creature defending player controls"); + private static final FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); } public DistractingGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{W}", + "Clever Distraction", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.CleverDistraction.class; + // Distracting Geist + this.getLeftHalfCard().setPT(2, 1); // Whenever Distracting Geist attacks, tap target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new TapTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + + // Clever Distraction + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {4}{W} - this.addAbility(new DisturbAbility(this, "{4}{W}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{W}")); + + // Enchanted creature has "Whenever this creature attacks, tap target creature defending player controls." + Ability ability2 = new AttacksTriggeredAbility(new TapTargetEffect()).setTriggerPhrase("Whenever this creature attacks, "); + ability2.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability2, AttachmentType.AURA))); + + // If Clever Distracting would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DistractingGeist(final DistractingGeist card) { diff --git a/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java b/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java index 129e98d02db..5c6d9e4a605 100644 --- a/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java +++ b/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java @@ -1,7 +1,7 @@ package mage.cards.d; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; @@ -9,15 +9,18 @@ import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.HumanWizardToken; @@ -27,7 +30,7 @@ import java.util.UUID; /** * @author fireshoes */ -public final class DocentOfPerfection extends CardImpl { +public final class DocentOfPerfection extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledPermanent(SubType.WIZARD), ComparisonType.MORE_THAN, 2 @@ -35,22 +38,27 @@ public final class DocentOfPerfection extends CardImpl { private static final Hint hint = new ValueHint( "Wizards you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.WIZARD)) ); + private static final FilterPermanent filterWizard = new FilterPermanent("Wizards"); + + static { + filterWizard.add(SubType.WIZARD.getPredicate()); + } public DocentOfPerfection(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); - this.subtype.add(SubType.INSECT); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(5); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT, SubType.HORROR}, "{3}{U}{U}", + "Final Iteration", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.INSECT}, "" + ); - this.secondSideCardClazz = mage.cards.f.FinalIteration.class; + // Docent of Perfection + this.getLeftHalfCard().setPT(5, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever you cast an instant or sorcery spell, create a 1/1 blue Human Wizard creature token. // Then if you control three or more Wizards, transform Docent of Perfection. - this.addAbility(new TransformAbility()); Ability ability = new SpellCastControllerTriggeredAbility( new CreateTokenEffect(new HumanWizardToken()), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false @@ -59,7 +67,28 @@ public final class DocentOfPerfection extends CardImpl { new TransformSourceEffect(), condition, "Then if you control three or more Wizards, transform {this}" )); - this.addAbility(ability.addHint(hint)); + this.getLeftHalfCard().addAbility(ability.addHint(hint)); + + // Final Iteration + this.getRightHalfCard().setPT(6, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Wizards you control get +2/+1 and have flying. + Ability ability2 = new SimpleStaticAbility(new BoostControlledEffect( + 2, 1, Duration.WhileOnBattlefield, filterWizard, false + )); + ability2.addEffect(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filterWizard + ).setText("and have flying")); + this.getRightHalfCard().addAbility(ability2); + + // Whenever you cast an instant or sorcery spell, create a 1/1 blue Human Wizard creature token. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new HumanWizardToken()), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); } private DocentOfPerfection(final DocentOfPerfection card) { diff --git a/Mage.Sets/src/mage/cards/d/DoctorDoom.java b/Mage.Sets/src/mage/cards/d/DoctorDoom.java new file mode 100644 index 00000000000..1006beb5aad --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoctorDoom.java @@ -0,0 +1,83 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.DoombotToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DoctorDoom extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("you control an artifact creature or a Plan"); + + static { + filter.add(Predicates.or( + Predicates.and( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + ), + SubType.PLAN.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition); + + public DoctorDoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Doctor Doom enters, create two 3/3 colorless Robot Villain artifact creature tokens named Doombot. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new DoombotToken(), 2))); + + // As long as you control an artifact creature or a Plan, Doctor Doom has indestructible. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), condition, + "as long as you control an artifact creature or a Plan, {this} has indestructible" + )).addHint(hint)); + + // At the beginning of your end step, you draw a card and lose 1 life. + Ability ability = new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1, true)); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private DoctorDoom(final DoctorDoom card) { + super(card); + } + + @Override + public DoctorDoom copy() { + return new DoctorDoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java b/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java new file mode 100644 index 00000000000..1f264b2ade7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DollmakersShopPorcelainGallery.java @@ -0,0 +1,57 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessAllEffect; +import mage.abilities.hint.ValueHint; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Duration; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.ToyToken; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class DollmakersShopPorcelainGallery extends RoomCard { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("non-Toy creatures you control"); + + static { + filter.add(Predicates.not(SubType.TOY.getPredicate())); + } + + public DollmakersShopPorcelainGallery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{1}{W}", "{4}{W}{W}"); + this.subtype.add(SubType.ROOM); + + // Dollmaker's Shop: Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token. + Ability left = new AttacksPlayerWithCreaturesTriggeredAbility(new CreateTokenEffect(new ToyToken()), filter, SetTargetPointer.NONE); + this.getLeftHalfCard().addAbility(left); + + // Porcelain Gallery: Creatures you control have base power and toughness each equal to the number of creatures you control. + Ability right = new SimpleStaticAbility(new SetBasePowerToughnessAllEffect( + CreaturesYouControlCount.PLURAL, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("Creatures you control have base power and toughness each equal to the number of creatures you control")); + right.addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.PLURAL)); + this.getRightHalfCard().addAbility(right); + } + + private DollmakersShopPorcelainGallery(final DollmakersShopPorcelainGallery card) { + super(card); + } + + @Override + public DollmakersShopPorcelainGallery copy() { + return new DollmakersShopPorcelainGallery(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DonatelloRadScientist.java b/Mage.Sets/src/mage/cards/d/DonatelloRadScientist.java new file mode 100644 index 00000000000..27bbbbd153e --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DonatelloRadScientist.java @@ -0,0 +1,52 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DonatelloRadScientist extends CardImpl { + + public DonatelloRadScientist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Donatello enters, tap up to three target creatures your opponents control. Put a stun counter on each of them. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("Put a stun counter on each of them")); + ability.addTarget(new TargetOpponentsCreaturePermanent(0, 3)); + this.addAbility(ability); + } + + private DonatelloRadScientist(final DonatelloRadScientist card) { + super(card); + } + + @Override + public DonatelloRadScientist copy() { + return new DonatelloRadScientist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DonatelloTheBrains.java b/Mage.Sets/src/mage/cards/d/DonatelloTheBrains.java new file mode 100644 index 00000000000..22e8569ce9c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DonatelloTheBrains.java @@ -0,0 +1,89 @@ +package mage.cards.d; + +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.MutagenToken; +import mage.game.permanent.token.Token; +import mage.util.CardUtil; + +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DonatelloTheBrains extends CardImpl { + + public DonatelloTheBrains(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // If one or more tokens would be created under your control, those tokens plus a Mutagen token are created instead. + this.addAbility(new SimpleStaticAbility(new DonatelloTheBrainsReplacementEffect())); + + // Partner--Character select + this.addAbility(PartnerVariantType.CHARACTER_SELECT.makeAbility()); + } + + private DonatelloTheBrains(final DonatelloTheBrains card) { + super(card); + } + + @Override + public DonatelloTheBrains copy() { + return new DonatelloTheBrains(this); + } +} + +class DonatelloTheBrainsReplacementEffect extends ReplacementEffectImpl { + + DonatelloTheBrainsReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + this.staticText = "if one or more tokens would be created under your control, " + + "those tokens plus a Mutagen token are created instead"; + } + + private DonatelloTheBrainsReplacementEffect(final DonatelloTheBrainsReplacementEffect effect) { + super(effect); + } + + @Override + public DonatelloTheBrainsReplacementEffect copy() { + return new DonatelloTheBrainsReplacementEffect(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) { + Map tokens = ((CreateTokenEvent) event).getTokens(); + Token token = CardUtil + .castStream(tokens.values(), MutagenToken.class) + .findAny() + .orElseGet(MutagenToken::new); + tokens.compute(token, CardUtil::setOrIncrementValue); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DonnieAndAprilAdorkableDuo.java b/Mage.Sets/src/mage/cards/d/DonnieAndAprilAdorkableDuo.java new file mode 100644 index 00000000000..2e765a96713 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DonnieAndAprilAdorkableDuo.java @@ -0,0 +1,112 @@ +package mage.cards.d; + +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.DrawCardTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPlayer; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DonnieAndAprilAdorkableDuo extends CardImpl { + + private static final FilterPlayer filter0 = new FilterPlayer("a different player"); + private static final FilterPlayer filter1 = new FilterPlayer(); + private static final FilterPlayer filter2 = new FilterPlayer(); + + static { + filter1.add(new AnotherTargetPredicate(1, true)); + filter2.add(new AnotherTargetPredicate(2, true)); + } + + public DonnieAndAprilAdorkableDuo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Donnie & April enter, choose one or both. Each mode must target a different player. + // * Target player draws two cards. + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardTargetEffect(2)); + ability.addTarget(new TargetPlayer(filter1).withChooseHint("to draw a card")); + ability.getModes().setMinModes(1); + ability.getModes().setMaxModes(2); + ability.getModes().setLimitUsageByOnce(false); + ability.getModes().setMaxModesFilter(filter0); + + // * Target player returns an artifact, instant, or sorcery card from their graveyard to their hand. + ability.addMode(new Mode(new DonnieAndAprilAdorkableDuoEffect()) + .addTarget(new TargetPlayer(filter2).withChooseHint("to return a card from their graveyard to their hand"))); + this.addAbility(ability); + } + + private DonnieAndAprilAdorkableDuo(final DonnieAndAprilAdorkableDuo card) { + super(card); + } + + @Override + public DonnieAndAprilAdorkableDuo copy() { + return new DonnieAndAprilAdorkableDuo(this); + } +} + +class DonnieAndAprilAdorkableDuoEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("artifact, instant, or sorcery card"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.INSTANT.getPredicate(), + CardType.SORCERY.getPredicate() + )); + } + + DonnieAndAprilAdorkableDuoEffect() { + super(Outcome.Benefit); + staticText = "target player returns an artifact, instant, or sorcery card from their graveyard to their hand"; + } + + private DonnieAndAprilAdorkableDuoEffect(final DonnieAndAprilAdorkableDuoEffect effect) { + super(effect); + } + + @Override + public DonnieAndAprilAdorkableDuoEffect copy() { + return new DonnieAndAprilAdorkableDuoEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null || player.getGraveyard().count(filter, game) < 1) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(filter); + player.choose(Outcome.ReturnToHand, player.getGraveyard(), 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/d/DormantGrove.java b/Mage.Sets/src/mage/cards/d/DormantGrove.java index 3db92560395..b0bbfe62961 100644 --- a/Mage.Sets/src/mage/cards/d/DormantGrove.java +++ b/Mage.Sets/src/mage/cards/d/DormantGrove.java @@ -1,47 +1,62 @@ package mage.cards.d; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class DormantGrove extends CardImpl { +public final class DormantGrove extends TransformingDoubleFacedCard { public DormantGrove(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); - - this.secondSideCardClazz = mage.cards.g.GnarledGrovestrider.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{G}", + "Gnarled Grovestrider", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK}, "G"); + // Dormant Grove // At the beginning of combat on your turn, put a +1/+1 counter on target creature you control. // Then if that creature has toughness 6 or greater, transform Dormant Grove. - this.addAbility(new TransformAbility()); - - Ability ability = new BeginningOfCombatTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - ); + Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), DormatGroveCondition.instance, "Then if that creature has toughness 6 or greater, transform {this}" )); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Gnarled Grovestrider + this.getRightHalfCard().setPT(3, 6); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Other creatures you control have vigilance. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES, true + ))); } private DormantGrove(final DormantGrove card) { diff --git a/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java b/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java index eb57714d748..2987e7c54e2 100644 --- a/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java +++ b/Mage.Sets/src/mage/cards/d/DorotheaVengefulVictim.java @@ -1,45 +1,73 @@ package mage.cards.d; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.token.DorotheasRetributionSpiritToken; +import mage.game.permanent.token.Token; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTargets; import java.util.UUID; /** * @author TheElk801 */ -public final class DorotheaVengefulVictim extends CardImpl { +public final class DorotheaVengefulVictim extends TransformingDoubleFacedCard { public DorotheaVengefulVictim(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{W}{U}", + "Dorothea's Retribution", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "WU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.d.DorotheasRetribution.class; + // Dorothea, Vengeful Victim + this.getLeftHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Dorothea, Vengeful Victim attacks or blocks, sacrifice it at end of combat. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + this.getLeftHalfCard().addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect()) ).setText("sacrifice it at end of combat"), false)); + + // Dorothea's Retribution + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {1}{W}{U} - this.addAbility(new DisturbAbility(this, "{1}{W}{U}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}{U}")); + + // Enchanted creature has "Whenever this creature attacks, create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat." + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + new AttacksTriggeredAbility(new DorotheasRetributionEffect()).setTriggerPhrase("Whenever this creature attacks, "), + AttachmentType.AURA + ))); + + // If Dorothea's Retribution would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DorotheaVengefulVictim(final DorotheaVengefulVictim card) { @@ -51,3 +79,32 @@ public final class DorotheaVengefulVictim extends CardImpl { return new DorotheaVengefulVictim(this); } } + +class DorotheasRetributionEffect extends OneShotEffect { + + DorotheasRetributionEffect() { + super(Outcome.Benefit); + staticText = "create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat"; + } + + private DorotheasRetributionEffect(final DorotheasRetributionEffect effect) { + super(effect); + } + + @Override + public DorotheasRetributionEffect copy() { + return new DorotheasRetributionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new DorotheasRetributionSpiritToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility( + new SacrificeTargetEffect() + .setTargetPointer(new FixedTargets(token, game)) + .setText("sacrifice that token") + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java b/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java deleted file mode 100644 index 688994337d7..00000000000 --- a/Mage.Sets/src/mage/cards/d/DorotheasRetribution.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.d; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -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.game.Game; -import mage.game.permanent.token.DorotheasRetributionSpiritToken; -import mage.game.permanent.token.Token; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTargets; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DorotheasRetribution extends CardImpl { - - public DorotheasRetribution(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has "Whenever this creature attacks, create a 4/4 white Spirit creature token with flying that's tapped and attacking. Sacrifice that token at end of combat." - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( - new AttacksTriggeredAbility(new DorotheasRetributionEffect()) - .setTriggerPhrase("Whenever this creature attacks, "), - AttachmentType.AURA - ))); - - // If Dorothea's Retribution would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DorotheasRetribution(final DorotheasRetribution card) { - super(card); - } - - @Override - public DorotheasRetribution copy() { - return new DorotheasRetribution(this); - } -} - -class DorotheasRetributionEffect extends OneShotEffect { - - DorotheasRetributionEffect() { - super(Outcome.Benefit); - staticText = "create a 4/4 white Spirit creature token with flying " + - "that's tapped and attacking. Sacrifice that token at end of combat"; - } - - private DorotheasRetributionEffect(final DorotheasRetributionEffect effect) { - super(effect); - } - - @Override - public DorotheasRetributionEffect copy() { - return new DorotheasRetributionEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Token token = new DorotheasRetributionSpiritToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); - game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility( - new SacrificeTargetEffect() - .setTargetPointer(new FixedTargets(token, game)) - .setText("sacrifice that token") - ), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DoseOfDawnglow.java b/Mage.Sets/src/mage/cards/d/DoseOfDawnglow.java new file mode 100644 index 00000000000..47b25ae0b6d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DoseOfDawnglow.java @@ -0,0 +1,39 @@ +package mage.cards.d; + +import mage.abilities.condition.common.IsMainPhaseCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.keyword.BlightControllerEffect; +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 DoseOfDawnglow extends CardImpl { + + public DoseOfDawnglow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); + + // Return target creature card from your graveyard to the battlefield. Then if it isn't your main phase, blight 2. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new BlightControllerEffect(2), IsMainPhaseCondition.NOT_YOURS + ).concatBy("Then")); + } + + private DoseOfDawnglow(final DoseOfDawnglow card) { + super(card); + } + + @Override + public DoseOfDawnglow copy() { + return new DoseOfDawnglow(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinsAcuity.java b/Mage.Sets/src/mage/cards/d/DovinsAcuity.java index 07386d65811..163eb593436 100644 --- a/Mage.Sets/src/mage/cards/d/DovinsAcuity.java +++ b/Mage.Sets/src/mage/cards/d/DovinsAcuity.java @@ -36,7 +36,7 @@ public final class DovinsAcuity extends CardImpl { // Whenever you cast an instant spell during your main phase, you may return Dovin's Acuity to its owner's hand. this.addAbility(new SpellCastControllerTriggeredAbility( new ReturnToHandSourceEffect(true), filter, true - ).withTriggerCondition(IsMainPhaseCondition.YOUR).setTriggerPhrase("Whenever you cast an instant spell during your main phase, ")); + ).withTriggerCondition(IsMainPhaseCondition.YOURS).setTriggerPhrase("Whenever you cast an instant spell during your main phase, ")); } private DovinsAcuity(final DovinsAcuity card) { diff --git a/Mage.Sets/src/mage/cards/d/DowsingDagger.java b/Mage.Sets/src/mage/cards/d/DowsingDagger.java index a5b02e21193..6f3ff63dd5f 100644 --- a/Mage.Sets/src/mage/cards/d/DowsingDagger.java +++ b/Mage.Sets/src/mage/cards/d/DowsingDagger.java @@ -1,18 +1,19 @@ - package mage.cards.d; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -24,29 +25,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DowsingDagger extends CardImpl { +public final class DowsingDagger extends TransformingDoubleFacedCard { public DowsingDagger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.subtype.add(SubType.EQUIPMENT); - - this.secondSideCardClazz = mage.cards.l.LostVale.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{2}", + "Lost Vale", + new CardType[]{CardType.LAND}, new SubType[]{}, ""); + // Dowsing Dagger // When Dowsing Dagger enters the battlefield, target opponent creates two 0/2 green Plant creature tokens with defender. Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenTargetEffect(new DefenderPlantToken(), 2), false); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Equipped creature gets +2/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); // Whenever equipped creature deals combat damage to a player, you may transform Dowsing Dagger. - this.addAbility(new TransformAbility()); - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new TransformSourceEffect(), "equipped", true)); + this.getLeftHalfCard().addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new TransformSourceEffect(), "equipped", true)); // Equip 2 - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), false)); + this.getLeftHalfCard().addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), false)); + + // Lost Vale + // T: Add three mana of any one color. + this.getRightHalfCard().addAbility(new SimpleManaAbility(new AddManaOfAnyColorEffect(3), new TapSourceCost())); } private DowsingDagger(final DowsingDagger card) { diff --git a/Mage.Sets/src/mage/cards/d/DowsingDevice.java b/Mage.Sets/src/mage/cards/d/DowsingDevice.java index d6e3c299bbe..53025077ab2 100644 --- a/Mage.Sets/src/mage/cards/d/DowsingDevice.java +++ b/Mage.Sets/src/mage/cards/d/DowsingDevice.java @@ -1,40 +1,49 @@ package mage.cards.d; import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.hint.common.ArtifactYouControlHint; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.RedManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class DowsingDevice extends CardImpl { +public final class DowsingDevice extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, ComparisonType.MORE_THAN, 3 ); public DowsingDevice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}"); - this.secondSideCardClazz = mage.cards.g.GeodeGrotto.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{R}", + "Geode Grotto", + new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, ""); + // Dowsing Device // Whenever Dowsing Device or another artifact you control enters, up to one target creature you control gets +1/+0 and gains haste until end of turn. Then transform Dowsing Device if you control four or more artifacts. - this.addAbility(new TransformAbility()); Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( new BoostTargetEffect(1, 0) .setText("up to one target creature you control gets +1/+0"), @@ -43,11 +52,24 @@ public final class DowsingDevice extends CardImpl { ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) .setText("and gains haste until end of turn")); ability.addEffect(new ConditionalOneShotEffect( - new TransformSourceEffect(), condition, "Then " + - "transform {this} if you control four or more artifacts" + new TransformSourceEffect(), condition, "Then transform {this} if you control four or more artifacts" )); ability.addTarget(new TargetControlledCreaturePermanent(0, 1)); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); + this.getLeftHalfCard().addAbility(ability.addHint(ArtifactYouControlHint.instance)); + + // Geode Grotto + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); + + // {2}{R}, {T}: Until end of turn, target creature gains haste and gets +X/+0, where X is the number of artifacts you control. Activate only as a sorcery. + Ability ability2 = new ActivateAsSorceryActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setText("Until end of turn, target creature gains haste"), new ManaCostsImpl<>("{2}{R}")); + ability2.addCost(new TapSourceCost()); + ability2.addEffect(new BoostTargetEffect( + ArtifactYouControlCount.instance, StaticValue.get(0) + ).setText("and gets +X/+0, where X is the number of artifacts you control")); + ability2.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2.addHint(ArtifactYouControlHint.instance)); } private DowsingDevice(final DowsingDevice card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java b/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java deleted file mode 100644 index 3def1f2d789..00000000000 --- a/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java +++ /dev/null @@ -1,91 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; -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 DiesThisOrAnotherTriggeredAbility( - 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() - .getCardsOwned(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/DragonflySwarm.java b/Mage.Sets/src/mage/cards/d/DragonflySwarm.java new file mode 100644 index 00000000000..35683a3dd5f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DragonflySwarm.java @@ -0,0 +1,68 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; +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.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DragonflySwarm extends CardImpl { + + private static final FilterCard filter = new FilterCard("noncreature, nonland cards"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(filter); + + public DragonflySwarm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); + + this.subtype.add(SubType.DRAGON); + this.subtype.add(SubType.INSECT); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Ward {1} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + + // This creature's power is equal to the number of noncreature, nonland cards in your graveyard. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerSourceEffect(xValue))); + + // When this creature dies, if there's a Lesson card in your graveyard, draw a card. + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(LessonsInGraveCondition.ONE).addHint(LessonsInGraveCondition.getHint())); + } + + private DragonflySwarm(final DragonflySwarm card) { + super(card); + } + + @Override + public DragonflySwarm copy() { + return new DragonflySwarm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java b/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java index 45469a4de18..0f9d6fcbdd3 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java +++ b/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java @@ -16,6 +16,7 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.EachTargetPointer; import java.util.UUID; @@ -40,7 +41,7 @@ public final class DragonsparkReactor extends CardImpl { 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) + ).setTargetPointer(new EachTargetPointer()), new GenericManaCost(4) ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/d/DrakusethMawOfFlames.java b/Mage.Sets/src/mage/cards/d/DrakusethMawOfFlames.java index 5b05e77d8d3..be989545f08 100644 --- a/Mage.Sets/src/mage/cards/d/DrakusethMawOfFlames.java +++ b/Mage.Sets/src/mage/cards/d/DrakusethMawOfFlames.java @@ -3,20 +3,16 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; 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.constants.SuperType; import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetPermanentOrPlayer; @@ -26,6 +22,7 @@ import java.util.UUID; * @author TheElk801 */ public final class DrakusethMawOfFlames extends CardImpl { + private static final FilterPermanentOrPlayer filter = new FilterAnyTarget("any target"); static { @@ -45,7 +42,8 @@ public final class DrakusethMawOfFlames extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Drakuseth, Maw of Flames attacks, it deals 4 damage to any target and 3 damage to each of up to two other targets. - Ability ability = new AttacksTriggeredAbility(new DrakusethMawOfFlamesEffect(), false); + Ability ability = new AttacksTriggeredAbility(new DamageTargetAndTargetEffect(4, 3) + .setText("it deals 4 damage to any target and 3 damage to each of up to two other targets")); ability.addTarget(new TargetAnyTarget().withChooseHint("to deal 4 damage").setTargetTag(1)); ability.addTarget(new TargetPermanentOrPlayer( 0, 2, filter, false @@ -62,43 +60,3 @@ public final class DrakusethMawOfFlames extends CardImpl { return new DrakusethMawOfFlames(this); } } - -class DrakusethMawOfFlamesEffect extends OneShotEffect { - - DrakusethMawOfFlamesEffect() { - super(Outcome.Damage); - staticText = "it deals 4 damage to any target and 3 damage to each of " - + "up to two other targets."; - } - - private DrakusethMawOfFlamesEffect(final DrakusethMawOfFlamesEffect effect) { - super(effect); - } - - @Override - public DrakusethMawOfFlamesEffect copy() { - return new DrakusethMawOfFlamesEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - damage(4, source.getTargets().get(0).getFirstTarget(), game, source); - source.getTargets() - .get(1) - .getTargets() - .stream() - .forEach(targetId -> damage(3, targetId, game, source)); - return true; - } - - private static void damage(int damage, UUID targetId, Game game, Ability source) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.damage(damage, source.getSourceId(), source, game, false, true); - } - Player player = game.getPlayer(targetId); - if (player != null) { - player.damage(damage, source.getSourceId(), source, game); - } - } -} diff --git a/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java b/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java index 59db469c383..4d30803171c 100644 --- a/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java +++ b/Mage.Sets/src/mage/cards/d/DraugrNecromancer.java @@ -182,8 +182,8 @@ class DraugrNecromancerSpendAnyManaEffect extends AsThoughEffectImpl implements cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } else if (card instanceof CardWithSpellOption) { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); - } else if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + } else if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/d/DreadOsseosaur.java b/Mage.Sets/src/mage/cards/d/DreadOsseosaur.java deleted file mode 100644 index aea68c4293c..00000000000 --- a/Mage.Sets/src/mage/cards/d/DreadOsseosaur.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.d; - -import mage.MageInt; -import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.effects.common.MillCardsControllerEffect; -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 DreadOsseosaur extends CardImpl { - - public DreadOsseosaur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DINOSAUR); - this.subtype.add(SubType.SKELETON); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setBlack(true); - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Whenever Dread Osseosaur enters the battlefield or attacks, you may mill two cards. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( - new MillCardsControllerEffect(2), true - )); - } - - private DreadOsseosaur(final DreadOsseosaur card) { - super(card); - } - - @Override - public DreadOsseosaur copy() { - return new DreadOsseosaur(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java b/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java deleted file mode 100644 index dd67d25ed9d..00000000000 --- a/Mage.Sets/src/mage/cards/d/DrogskolArmaments.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.d; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.keyword.DisturbAbility; -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.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class DrogskolArmaments extends CardImpl { - - public DrogskolArmaments(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature gets +2/+2. - this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 2))); - - // If Drogskol Armaments would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private DrogskolArmaments(final DrogskolArmaments card) { - super(card); - } - - @Override - public DrogskolArmaments copy() { - return new DrogskolArmaments(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java index c83c5ccffe5..5ff5195f54b 100644 --- a/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java +++ b/Mage.Sets/src/mage/cards/d/DrogskolInfantry.java @@ -1,31 +1,52 @@ package mage.cards.d; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 TheElk801 */ -public final class DrogskolInfantry extends CardImpl { +public final class DrogskolInfantry extends TransformingDoubleFacedCard { public DrogskolInfantry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "{1}{W}", + "Drogskol Armaments", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W"); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.d.DrogskolArmaments.class; + // Drogskol Infantry + this.getLeftHalfCard().setPT(2, 2); + + + // Drogskol Armaments + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {3}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}")); + // needs to be added after enchant ability to set correct target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}")); + + // Enchanted creature gets +2/+2. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 2))); + + // If Drogskol Armaments would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private DrogskolInfantry(final DrogskolInfantry card) { diff --git a/Mage.Sets/src/mage/cards/d/DronepackKindred.java b/Mage.Sets/src/mage/cards/d/DronepackKindred.java deleted file mode 100644 index 3b3e4b5b1a1..00000000000 --- a/Mage.Sets/src/mage/cards/d/DronepackKindred.java +++ /dev/null @@ -1,48 +0,0 @@ - -package mage.cards.d; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -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; - -/** - * - * @author fireshoes - */ -public final class DronepackKindred extends CardImpl { - - public DronepackKindred(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(7); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // {1}: Dronepack Kindred gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(1))); - } - - private DronepackKindred(final DronepackKindred card) { - super(card); - } - - @Override - public DronepackKindred copy() { - return new DronepackKindred(this); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DryadOfTheIlysianGrove.java b/Mage.Sets/src/mage/cards/d/DryadOfTheIlysianGrove.java index 7e81a8956d2..cf76238a377 100644 --- a/Mage.Sets/src/mage/cards/d/DryadOfTheIlysianGrove.java +++ b/Mage.Sets/src/mage/cards/d/DryadOfTheIlysianGrove.java @@ -31,7 +31,7 @@ public final class DryadOfTheIlysianGrove extends CardImpl { )); // Lands you control are every basic land type in addition to their other types. - this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect())); + this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect(Duration.WhileOnBattlefield))); } private DryadOfTheIlysianGrove(final DryadOfTheIlysianGrove card) { diff --git a/Mage.Sets/src/mage/cards/d/DuelistsFlame.java b/Mage.Sets/src/mage/cards/d/DuelistsFlame.java index 01eae7cd35d..83c3d6b6475 100644 --- a/Mage.Sets/src/mage/cards/d/DuelistsFlame.java +++ b/Mage.Sets/src/mage/cards/d/DuelistsFlame.java @@ -42,7 +42,7 @@ public final class DuelistsFlame extends CardImpl { // Until end of turn, target blocked creature you control gets +X/+0 and gains trample and "Whenever this creature deals combat damage to a player, look at that many cards from the top of your library. Exile up to one nonland card from among them 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." this.getSpellAbility().addEffect(new BoostTargetEffect(GetXValue.instance, StaticValue.get(0)) .setText("until end of turn, target blocked creature you control gets +X/+0")); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and has trample")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()).setText("and gains trample")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect( new DealsCombatDamageToAPlayerTriggeredAbility(new DuelistsFlameEffect()) ).setText("and \"Whenever this creature deals combat damage to a player, " + diff --git a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java index 695fb926a45..23b20194dae 100644 --- a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java +++ b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java @@ -1,45 +1,57 @@ package mage.cards.d; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; + +import java.util.UUID; /** * @author fireshoes */ -public final class DuskwatchRecruiter extends CardImpl { +public final class DuskwatchRecruiter extends TransformingDoubleFacedCard { public DuskwatchRecruiter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{1}{G}", + "Krallenhorde Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.k.KrallenhordeHowler.class; + // Duskwatch Recruiter + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - // {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( + // {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. + Ability ability = new SimpleActivatedAbility( new LookLibraryAndPickControllerEffect(3, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY), - new ManaCostsImpl<>("{2}{G}"))); + new ManaCostsImpl<>("{2}{G}") + ); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Duskwatch Recruiter. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Krallenhorde Howler + this.getRightHalfCard().setPT(3, 3); + + // Creature spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + new SpellsCostReductionControllerEffect(new FilterCreatureCard("creature spells"), 1) + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Howler. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private DuskwatchRecruiter(final DuskwatchRecruiter card) { diff --git a/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java b/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java new file mode 100644 index 00000000000..8921f751bf4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DutifulKnowledgeSeeker.java @@ -0,0 +1,51 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.PutIntoLibraryOneOrMoreTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +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.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DutifulKnowledgeSeeker extends CardImpl { + + public DutifulKnowledgeSeeker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.FOX); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever one or more cards are put into a library from anywhere, put a +1/+1 counter on this creature. + this.addAbility(new PutIntoLibraryOneOrMoreTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + )); + + // {3}: Put target card from a graveyard on the bottom of its owner's library. + Ability ability = new SimpleActivatedAbility(new PutOnLibraryTargetEffect(false), new GenericManaCost(3)); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + } + + private DutifulKnowledgeSeeker(final DutifulKnowledgeSeeker card) { + super(card); + } + + @Override + public DutifulKnowledgeSeeker copy() { + return new DutifulKnowledgeSeeker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java index 6cafeb67f3c..bcdfce26d32 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java @@ -42,7 +42,7 @@ public final class DwarvenSeaClan extends CardImpl { // {tap}: Choose target attacking or blocking creature whose controller controls an Island. Dwarven Sea Clan deals 2 damage to that creature at end of combat. Activate this ability only before the end of combat step. Ability ability = new ActivateIfConditionActivatedAbility( new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( - new DamageTargetEffect(2, true, "that creature") + new DamageTargetEffect(2).withTargetDescription("that creature") )).setText("Choose target attacking or blocking creature whose controller controls an Island. " + "{this} deals 2 damage to that creature at end of combat."), new TapSourceCost(), BeforeEndCombatCondition.getInstance() diff --git a/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java b/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java new file mode 100644 index 00000000000..72f9f07455d --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthKingdomGeneral.java @@ -0,0 +1,56 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.PutCounterOnPermanentTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.EffectKeyValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthKingdomGeneral extends CardImpl { + + private static final DynamicValue xValue = new EffectKeyValue("countersAdded", "that much"); + + public EarthKingdomGeneral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, earthbend 2. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(2)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // Whenever you put one or more +1/+1 counters on a creature, you may gain that much life. Do this only once each turn. + this.addAbility(new PutCounterOnPermanentTriggeredAbility( + new GainLifeEffect(xValue), CounterType.P1P1, StaticFilters.FILTER_PERMANENT_CREATURE + ).setDoOnlyOnceEachTurn(true)); + } + + private EarthKingdomGeneral(final EarthKingdomGeneral card) { + super(card); + } + + @Override + public EarthKingdomGeneral copy() { + return new EarthKingdomGeneral(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthKingdomJailer.java b/Mage.Sets/src/mage/cards/e/EarthKingdomJailer.java new file mode 100644 index 00000000000..9c1ad504098 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthKingdomJailer.java @@ -0,0 +1,62 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthKingdomJailer extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent( + "artifact, creature, or enchantment an opponent controls with mana value 3 or greater" + ); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 2)); + } + + public EarthKingdomJailer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, exile up to one target artifact, creature, or enchantment an opponent controls with mana value 3 or greater until this creature leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileUntilSourceLeavesEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + } + + private EarthKingdomJailer(final EarthKingdomJailer card) { + super(card); + } + + @Override + public EarthKingdomJailer copy() { + return new EarthKingdomJailer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthKingdomProtectors.java b/Mage.Sets/src/mage/cards/e/EarthKingdomProtectors.java new file mode 100644 index 00000000000..d68b0b91fb8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthKingdomProtectors.java @@ -0,0 +1,61 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +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.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthKingdomProtectors extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.ALLY, "another target Ally you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public EarthKingdomProtectors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Sacrifice this creature: Another target Ally you control gains indestructible until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect(IndestructibleAbility.getInstance()), new SacrificeSourceCost() + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private EarthKingdomProtectors(final EarthKingdomProtectors card) { + super(card); + } + + @Override + public EarthKingdomProtectors copy() { + return new EarthKingdomProtectors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthKingsLieutenant.java b/Mage.Sets/src/mage/cards/e/EarthKingsLieutenant.java new file mode 100644 index 00000000000..49c957bad4e --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthKingsLieutenant.java @@ -0,0 +1,66 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +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 mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthKingsLieutenant extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.ALLY); + private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.ALLY, "another Ally you control"); + + static { + filter.add(AnotherPredicate.instance); + filter2.add(AnotherPredicate.instance); + } + + public EarthKingsLieutenant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When this creature enters, put a +1/+1 counter on each other Ally creature you control. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter) + .setText("put a +1/+1 counter on each other Ally creature you control") + )); + + // Whenever another Ally you control enters, put a +1/+1 counter on this creature. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter2 + )); + } + + private EarthKingsLieutenant(final EarthKingsLieutenant card) { + super(card); + } + + @Override + public EarthKingsLieutenant copy() { + return new EarthKingsLieutenant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthRumbleWrestlers.java b/Mage.Sets/src/mage/cards/e/EarthRumbleWrestlers.java new file mode 100644 index 00000000000..996a25299b1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthRumbleWrestlers.java @@ -0,0 +1,78 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.LandfallCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +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.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.watchers.common.LandfallWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthRumbleWrestlers extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(CardType.CREATURE.getPredicate()); + } + + private static final Condition condition = new CompoundCondition( + "you control a land creature or a land entered the battlefield under your control this turn", + new PermanentsOnTheBattlefieldCondition(filter), LandfallCondition.instance + ); + private static final Hint hint = new ConditionHint(condition); + + public EarthRumbleWrestlers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R/G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.PERFORMER); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // This creature gets +1/+0 and has trample as long as you control a land creature or a land entered the battlefield under your control this turn. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), + condition, "{this} gets +1/+0" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), + condition, "and has trample as long as you control a land creature " + + "or a land entered the battlefield under your control this turn" + )); + this.addAbility(ability.addHint(hint), new LandfallWatcher()); + } + + private EarthRumbleWrestlers(final EarthRumbleWrestlers card) { + super(card); + } + + @Override + public EarthRumbleWrestlers copy() { + return new EarthRumbleWrestlers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthbenderAscension.java b/Mage.Sets/src/mage/cards/e/EarthbenderAscension.java new file mode 100644 index 00000000000..d68fd37a8f9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthbenderAscension.java @@ -0,0 +1,95 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LandfallAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EarthbenderAscension extends CardImpl { + + public EarthbenderAscension(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // When this enchantment enters, earthbend 2. Then search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(2)); + ability.addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ).concatBy("Then")); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // Landfall -- Whenever a land you control enters, put a quest counter on this enchantment. When you do, if it has four or more quest counters on it, put a +1/+1 counter on target creature you control. It gains trample until end of turn. + this.addAbility(new LandfallAbility(new EarthbenderAscensionEffect())); + } + + private EarthbenderAscension(final EarthbenderAscension card) { + super(card); + } + + @Override + public EarthbenderAscension copy() { + return new EarthbenderAscension(this); + } +} + +class EarthbenderAscensionEffect extends OneShotEffect { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, ComparisonType.MORE_THAN, 3); + + EarthbenderAscensionEffect() { + super(Outcome.Benefit); + staticText = "put a quest counter on {this}. When you do, if it has four or more quest counters on it, " + + "put a +1/+1 counter on target creature you control. It gains trample until end of turn"; + } + + private EarthbenderAscensionEffect(final EarthbenderAscensionEffect effect) { + super(effect); + } + + @Override + public EarthbenderAscensionEffect copy() { + return new EarthbenderAscensionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || !permanent.addCounters(CounterType.QUEST.createInstance(), source, game)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false, "When you do, " + + "if it has four or more quest counters on it, put a +1/+1 counter on target creature you control. " + + "It gains trample until end of turn", condition + ); + ability.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance())); + ability.addTarget(new TargetControlledCreaturePermanent()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EarthenAlly.java b/Mage.Sets/src/mage/cards/e/EarthenAlly.java new file mode 100644 index 00000000000..e2e6715fc0b --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EarthenAlly.java @@ -0,0 +1,119 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.hint.Hint; +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.FilterControlledPermanent; +import mage.game.Game; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class EarthenAlly extends CardImpl { + + public EarthenAlly(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // This creature gets +1/+0 for each color among Allies you control. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + EarthenAllyValue.instance, StaticValue.get(0), Duration.WhileOnBattlefield + )).addHint(EarthenAllyHint.instance)); + + // {2}{W}{U}{B}{R}{G}: Earthbend 5. + Ability ability = new SimpleActivatedAbility( + new EarthbendTargetEffect(5), new ManaCostsImpl<>("{2}{W}{U}{B}{R}{G}") + ); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private EarthenAlly(final EarthenAlly card) { + super(card); + } + + @Override + public EarthenAlly copy() { + return new EarthenAlly(this); + } +} + +enum EarthenAllyValue implements DynamicValue { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ALLY); + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return getColors(game, sourceAbility).getColorCount(); + } + + static ObjectColor getColors(Game game, Ability sourceAbility) { + return game.getBattlefield() + .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game) + .stream() + .map(permanent -> permanent.getColor(game)) + .collect(Collectors.reducing((c1, c2) -> c1.union(c2))) + .orElseGet(ObjectColor::new); + } + + @Override + public EarthenAllyValue copy() { + return this; + } + + @Override + public String getMessage() { + return "color among Allies you control"; + } + + @Override + public String toString() { + return "1"; + } +} + +enum EarthenAllyHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + ObjectColor color = EarthenAllyValue.getColors(game, ability); + return "Colors among Allies you control: " + color.getColorCount() + + (color.getColorCount() > 0 + ? color + .getColors() + .stream() + .map(ObjectColor::getDescription) + .collect(Collectors.joining(", ", " (", ")")) + : ""); + } + + @Override + public Hint copy() { + return this; + } +} diff --git a/Mage.Sets/src/mage/cards/e/Earthshape.java b/Mage.Sets/src/mage/cards/e/Earthshape.java new file mode 100644 index 00000000000..713f6a7273b --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Earthshape.java @@ -0,0 +1,81 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Earthshape extends CardImpl { + + public Earthshape(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Earthbend 3. Then each creature you control with power less than or equal to that land's power gains hexproof and indestructible until end of turn. You gain hexproof until end of turn. + this.getSpellAbility().addEffect(new EarthshapeEffect()); + this.getSpellAbility().addTarget(new TargetControlledLandPermanent()); + this.getSpellAbility().addEffect(new GainAbilityControllerEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); + } + + private Earthshape(final Earthshape card) { + super(card); + } + + @Override + public Earthshape copy() { + return new Earthshape(this); + } +} + +class EarthshapeEffect extends OneShotEffect { + + EarthshapeEffect() { + super(Outcome.Benefit); + staticText = "Earthbend 3. Then each creature you control with power less than or equal " + + "to that land's power gains hexproof and indestructible until end of turn"; + } + + private EarthshapeEffect(final EarthshapeEffect effect) { + super(effect); + } + + @Override + public EarthshapeEffect copy() { + return new EarthshapeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + EarthbendTargetEffect.doEarthBend(permanent, 3, game, source); + game.processAction(); + int power = permanent.getPower().getValue(); + FilterPermanent filter = new FilterControlledCreaturePermanent(); + filter.add(new PowerPredicate(ComparisonType.OR_LESS, power)); + game.addEffect(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, filter), source); + game.addEffect(new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, filter), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EchoOfDeathsWail.java b/Mage.Sets/src/mage/cards/e/EchoOfDeathsWail.java deleted file mode 100644 index 03883109463..00000000000 --- a/Mage.Sets/src/mage/cards/e/EchoOfDeathsWail.java +++ /dev/null @@ -1,67 +0,0 @@ -package mage.cards.e; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.continuous.GainControlAllEffect; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.predicate.permanent.TokenPredicate; - -/** - * - * @author weirddan455 - */ -public final class EchoOfDeathsWail extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(SubType.RAT, "Rat tokens"); - - static { - filter.add(TokenPredicate.TRUE); - } - - public EchoOfDeathsWail(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // When Echo of Death's Wail enters the battlefield, gain control of all Rat tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainControlAllEffect(Duration.Custom, filter))); - - // Whenever Echo of Death's Wail attacks, you may sacrifice another creature. If you do, draw a card. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( - new DrawCardSourceControllerEffect(1), - new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) - ))); - } - - private EchoOfDeathsWail(final EchoOfDeathsWail card) { - super(card); - } - - @Override - public EchoOfDeathsWail copy() { - return new EchoOfDeathsWail(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java b/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java index 6002799d4a1..e1162a2a6a1 100644 --- a/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java +++ b/Mage.Sets/src/mage/cards/e/EcstaticAwakener.java @@ -1,45 +1,45 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class EcstaticAwakener extends CardImpl { +public final class EcstaticAwakener extends TransformingDoubleFacedCard { public EcstaticAwakener(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{B}", + "Awoken Demon", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.a.AwokenDemon.class; + // Ecstatic Awakener + this.getLeftHalfCard().setPT(1, 1); // {2}{B}, Sacrifice another creature: Draw a card, then transform Ecstatic Awakener. Activate only once each turn. - this.addAbility(new TransformAbility()); Ability ability = new LimitedTimesPerTurnActivatedAbility( Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{B}") ); ability.addEffect(new TransformSourceEffect().concatBy(", then")); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Awoken Demon + this.getRightHalfCard().setPT(4, 4); } private EcstaticAwakener(final EcstaticAwakener card) { diff --git a/Mage.Sets/src/mage/cards/e/EddieBrock.java b/Mage.Sets/src/mage/cards/e/EddieBrock.java index cc84afc2c29..feb1f69ff93 100644 --- a/Mage.Sets/src/mage/cards/e/EddieBrock.java +++ b/Mage.Sets/src/mage/cards/e/EddieBrock.java @@ -47,7 +47,7 @@ public final class EddieBrock extends ModalDoubleFacedCard { "Venom, Lethal Protector", new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SYMBIOTE, SubType.HERO, SubType.VILLAIN}, "{3}{B}{R}{G}" ); - this.getLeftHalfCard().setPT(5, 5); + this.getLeftHalfCard().setPT(3, 3); this.getRightHalfCard().setPT(5, 5); // When Eddie Brock enters, return target creature card with mana value 1 or less from your graveyard to the battlefield. diff --git a/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java b/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java index 8016a66a7f4..704a9315a79 100644 --- a/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java +++ b/Mage.Sets/src/mage/cards/e/EdgarCharmedGroom.java @@ -1,19 +1,27 @@ package mage.cards.e; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; +import mage.game.permanent.token.EdgarMarkovsCoffinVampireToken; import mage.players.Player; import java.util.UUID; @@ -21,28 +29,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EdgarCharmedGroom extends CardImpl { +public final class EdgarCharmedGroom extends TransformingDoubleFacedCard { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampires"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.BLOODLINE, 3); public EdgarCharmedGroom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.NOBLE}, "{2}{W}{B}", + "Edgar Markov's Coffin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "WB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.e.EdgarMarkovsCoffin.class; + // Edgar, Charmed Groom + this.getLeftHalfCard().setPT(4, 4); // Other Vampires you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( 1, 1, Duration.WhileOnBattlefield, filter, true ))); // When Edgar, Charmed Groom dies, return it to the battlefield transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new EdgarCharmedGroomEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new EdgarCharmedGroomEffect())); + + // Edgar Markov's Coffin + + // At the beginning of your upkeep, create a 1/1 white and black Vampire creature token with lifelink and put a bloodline counter on Edgar Markov's Coffin. Then if there are three or more bloodline counters on it, remove those counters and transform it. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new EdgarMarkovsCoffinVampireToken())); + ability.addEffect(new AddCountersSourceEffect(CounterType.BLOODLINE.createInstance()).concatBy("and")); + ability.addEffect(new ConditionalOneShotEffect( + new RemoveAllCountersSourceEffect(CounterType.BLOODLINE), condition, + "Then if there are three or more bloodline counters on it, remove those counters and transform it" + ).addEffect(new TransformSourceEffect())); + this.getRightHalfCard().addAbility(ability); } private EdgarCharmedGroom(final EdgarCharmedGroom card) { diff --git a/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java b/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java deleted file mode 100644 index 36ac4be28bd..00000000000 --- a/Mage.Sets/src/mage/cards/e/EdgarMarkovsCoffin.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.e; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.RemoveAllCountersSourceEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.game.permanent.token.EdgarMarkovsCoffinVampireToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EdgarMarkovsCoffin extends CardImpl { - - private static final Condition condition = new SourceHasCounterCondition(CounterType.BLOODLINE, 3); - - public EdgarMarkovsCoffin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // At the beginning of your upkeep, create a 1/1 white and black Vampire creature token with lifelink and put a bloodline counter on Edgar Markov's Coffin. Then if there are three or more bloodline counters on it, remove those counters and transform it. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new EdgarMarkovsCoffinVampireToken())); - ability.addEffect(new AddCountersSourceEffect(CounterType.BLOODLINE.createInstance()).concatBy("and")); - ability.addEffect(new ConditionalOneShotEffect( - new RemoveAllCountersSourceEffect(CounterType.BLOODLINE), condition, - "Then if there are three or more bloodline counters on it, remove those counters and transform it" - ).addEffect(new TransformSourceEffect())); - this.addAbility(ability); - } - - private EdgarMarkovsCoffin(final EdgarMarkovsCoffin card) { - super(card); - } - - @Override - public EdgarMarkovsCoffin copy() { - return new EdgarMarkovsCoffin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java b/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java index 66b05b103db..6ba0665ca81 100644 --- a/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java +++ b/Mage.Sets/src/mage/cards/e/EidolonOfTheGreatRevel.java @@ -49,7 +49,7 @@ class EidolonOfTheGreatRevelTriggeredAbility extends TriggeredAbilityImpl { public EidolonOfTheGreatRevelTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } diff --git a/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java b/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java index 65606b79efd..9c25983040b 100644 --- a/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java +++ b/Mage.Sets/src/mage/cards/e/EirduCarrierOfDawn.java @@ -1,21 +1,24 @@ package mage.cards.e; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; import mage.abilities.keyword.ConvokeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.PersistAbility; import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -25,7 +28,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EirduCarrierOfDawn extends CardImpl { +public final class EirduCarrierOfDawn extends TransformingDoubleFacedCard { private static final FilterNonlandCard filter = new FilterNonlandCard("creature spells you cast"); @@ -35,29 +38,45 @@ public final class EirduCarrierOfDawn extends CardImpl { } public EirduCarrierOfDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.GOD}, "{3}{W}{W}", + "Isilu, Carrier of Twilight", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.GOD}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.GOD); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.i.IsiluCarrierOfTwilight.class; + // Eirdu, Carrier of Dawn + this.getLeftHalfCard().setPT(5, 5); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Creature spells you cast have convoke. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); // At the beginning of your first main phase, you may pay {B}. If you do, transform Eirdu. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{B}")) - )); + Ability ability = new BeginningOfFirstMainTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{B}"))); + this.getLeftHalfCard().addAbility(ability); + + // Isilu, Carrier of Twilight + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Each other nontoken creature you control has persist. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new PersistAbility(), Duration.WhileControlled, + StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, true + ).setText("each other nontoken creature you control has persist"))); + + // At the beginning of your first main phase, you may pay {W}. If you do, transform Isilu. + this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{W}")))); } private EirduCarrierOfDawn(final EirduCarrierOfDawn card) { diff --git a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java index 8612d8b1dfa..bc9dcbfd858 100644 --- a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java +++ b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java @@ -1,20 +1,23 @@ package mage.cards.e; import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IntimidateAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.GameEvent; import java.util.Optional; import java.util.UUID; @@ -22,28 +25,43 @@ import java.util.UUID; /** * @author BetaSteward */ -public final class ElbrusTheBindingBlade extends CardImpl { +public final class ElbrusTheBindingBlade extends TransformingDoubleFacedCard { public ElbrusTheBindingBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{7}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.EQUIPMENT); - - this.secondSideCardClazz = mage.cards.w.WithengarUnbound.class; - this.addAbility(new TransformAbility()); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{7}", + "Withengar Unbound", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); + // Elbrus, the Binding Blade // Equipped creature gets +1/+0. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); // When equipped creature deals combat damage to a player, unattach Elbrus, the Binding Blade, then transform it. Ability ability = new DealsDamageToAPlayerAttachedTriggeredAbility( new ElbrusTheBindingBladeEffect(), "equipped", false ); ability.addEffect(new TransformSourceEffect(true).concatBy(", then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Equip {1} - this.addAbility(new EquipAbility(1, false)); + this.getLeftHalfCard().addAbility(new EquipAbility(1, false)); + + // Withengar Unbound + this.getRightHalfCard().setPT(13, 13); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Intimidate + this.getRightHalfCard().addAbility(IntimidateAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever a player loses the game, put thirteen +1/+1 counters on Withengar Unbound. + this.getRightHalfCard().addAbility(new WithengarUnboundTriggeredAbility()); } private ElbrusTheBindingBlade(final ElbrusTheBindingBlade card) { @@ -59,7 +77,7 @@ public final class ElbrusTheBindingBlade extends CardImpl { class ElbrusTheBindingBladeEffect extends OneShotEffect { ElbrusTheBindingBladeEffect() { super(Outcome.BecomeCreature); - staticText = "unattach {this}, then transform it"; + staticText = "unattach {this}"; } private ElbrusTheBindingBladeEffect(final ElbrusTheBindingBladeEffect effect) { @@ -77,3 +95,30 @@ class ElbrusTheBindingBladeEffect extends OneShotEffect { return new ElbrusTheBindingBladeEffect(this); } } + +class WithengarUnboundTriggeredAbility extends TriggeredAbilityImpl { + + WithengarUnboundTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(13)), false); + setTriggerPhrase("Whenever a player loses the game, "); + } + + private WithengarUnboundTriggeredAbility(final WithengarUnboundTriggeredAbility ability) { + super(ability); + } + + @Override + public WithengarUnboundTriggeredAbility copy() { + return new WithengarUnboundTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java b/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java index 34b05ea2ee8..d802d3cc68d 100644 --- a/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java +++ b/Mage.Sets/src/mage/cards/e/ElectroAssaultingBattery.java @@ -13,6 +13,7 @@ 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.players.Player; import mage.target.TargetPlayer; @@ -42,7 +43,8 @@ public final class ElectroAssaultingBattery extends CardImpl { this.addAbility(new SimpleStaticAbility(new YouDontLoseManaEffect(ManaType.RED))); // Whenever you cast an instant or sorcery spell, add {R}. - this.addAbility(new SpellCastControllerTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(Mana.RedMana(1)), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false)); // When Electro leaves the battlefield, you may pay x. When you do, he deals X damage to target player. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ElectroAssaultingBatteryEffect())); @@ -61,7 +63,7 @@ class ElectroAssaultingBatteryEffect extends OneShotEffect { ElectroAssaultingBatteryEffect() { super(Outcome.Damage); - staticText = "you may pay x. When you do, he deals X damage to target player"; + staticText = "you may pay {X}. When you do, he deals X damage to target player"; } private ElectroAssaultingBatteryEffect(final ElectroAssaultingBatteryEffect effect) { @@ -90,4 +92,4 @@ class ElectroAssaultingBatteryEffect extends OneShotEffect { } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/ElementalTeachings.java b/Mage.Sets/src/mage/cards/e/ElementalTeachings.java new file mode 100644 index 00000000000..b4c1fb32884 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElementalTeachings.java @@ -0,0 +1,37 @@ +package mage.cards.e; + +import mage.abilities.effects.common.search.SearchLibraryForFourDifferentCardsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElementalTeachings extends CardImpl { + + public ElementalTeachings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{G}"); + + this.subtype.add(SubType.LESSON); + + // 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 onto the battlefield tapped, then shuffle. + this.getSpellAbility().addEffect(new SearchLibraryForFourDifferentCardsEffect( + StaticFilters.FILTER_CARD_LANDS, PutCards.BATTLEFIELD_TAPPED, false + )); + } + + private ElementalTeachings(final ElementalTeachings card) { + super(card); + } + + @Override + public ElementalTeachings copy() { + return new ElementalTeachings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElephantMandrill.java b/Mage.Sets/src/mage/cards/e/ElephantMandrill.java new file mode 100644 index 00000000000..1096727695e --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElephantMandrill.java @@ -0,0 +1,69 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenAllEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactPermanent; +import mage.game.permanent.token.FoodToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElephantMandrill extends CardImpl { + + private static final FilterPermanent filter = new FilterArtifactPermanent("artifact your opponents control"); + + static { + filter.add(TargetController.OPPONENT.getOwnerPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Artifacts your opponents control", xValue); + + public ElephantMandrill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.MONKEY); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When this creature enters, each player creates a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenAllEffect(new FoodToken(), TargetController.EACH_PLAYER) + )); + + // At the beginning of combat on your turn, this creature gets +1/+1 until end of turn for each artifact your opponents control. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new BoostSourceEffect(xValue, xValue, Duration.EndOfTurn) + ).addHint(hint)); + } + + private ElephantMandrill(final ElephantMandrill card) { + super(card); + } + + @Override + public ElephantMandrill copy() { + return new ElephantMandrill(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EleshNorn.java b/Mage.Sets/src/mage/cards/e/EleshNorn.java index e1fe1dce1a4..c8898eda722 100644 --- a/Mage.Sets/src/mage/cards/e/EleshNorn.java +++ b/Mage.Sets/src/mage/cards/e/EleshNorn.java @@ -1,65 +1,104 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SourceDealsDamageToYouTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.IncubateEffect; +import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class EleshNorn extends CardImpl { +public final class EleshNorn extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("other creatures"); + private static final FilterPermanent argentFilter = new FilterPermanent("other permanents except for artifacts, lands, and Phyrexians"); static { filter.add(AnotherPredicate.instance); + argentFilter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); + argentFilter.add(Predicates.not(CardType.LAND.getPredicate())); + argentFilter.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); + argentFilter.add(AnotherPredicate.instance); } public EleshNorn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{2}{W}{W}", + "The Argent Etchings", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.PRAETOR); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.t.TheArgentEtchings.class; + // Elesh Norn + this.getLeftHalfCard().setPT(3, 5); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Whenever a source an opponent controls deals damage to you or a permanent you control, that source's controller loses 2 life unless they pay {1}. - this.addAbility(new SourceDealsDamageToYouTriggeredAbility(new EleshNornEffect(), StaticFilters.FILTER_PERMANENT, false)); + this.getLeftHalfCard().addAbility(new SourceDealsDamageToYouTriggeredAbility(new EleshNornEffect(), StaticFilters.FILTER_PERMANENT, false)); // {2}{W}, Sacrifice three other creatures: Exile Elesh Norn, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{2}{W}") ); ability.addCost(new SacrificeTargetCost(3, filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // The Argent Etchings + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Incubate 2 five times, then transform all Incubator tokens you control. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new TheArgentEtchingsEffect()); + + // II -- Creatures you control get +1/+1 and gain double strike until end of turn. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_II, + new BoostControlledEffect(1, 1, Duration.EndOfTurn) + .setText("creatures you control get +1/+1"), + new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and gain double strike until end of turn") + ); + + // III -- Destroy all other permanents except for artifacts, lands, and Phyrexians. Exile The Argent Etchings, then return it to the battlefield. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new DestroyAllEffect(argentFilter), + new ExileSourceAndReturnFaceUpEffect() + ); + this.getRightHalfCard().addAbility(sagaAbility); } private EleshNorn(final EleshNorn card) { @@ -103,3 +142,39 @@ class EleshNornEffect extends OneShotEffect { return player.loseLife(2, game, source, false) > 0; } } + +class TheArgentEtchingsEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.INCUBATOR); + + static { + filter.add(TokenPredicate.TRUE); + } + + TheArgentEtchingsEffect() { + super(Outcome.Benefit); + staticText = "incubate 2 five times, then transform all Incubator tokens you control"; + } + + private TheArgentEtchingsEffect(final TheArgentEtchingsEffect effect) { + super(effect); + } + + @Override + public TheArgentEtchingsEffect copy() { + return new TheArgentEtchingsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (int i = 0; i < 5; i++) { + IncubateEffect.doIncubate(2, game, source); + } + for (Permanent permanent : game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + )) { + permanent.transform(source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java b/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java index e89acc2d5c8..53b6d244900 100644 --- a/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java +++ b/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -34,7 +33,7 @@ public final class EllieBrickMaster extends CardImpl { this.addAbility(new EllieBrickMasterTriggeredAbility()); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private EllieBrickMaster(final EllieBrickMaster card) { diff --git a/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java b/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java index dc328efafab..881c500b698 100644 --- a/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java +++ b/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java @@ -8,13 +8,9 @@ import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.StaticFilters; import mage.target.TargetPlayer; @@ -44,7 +40,7 @@ public final class EllieVengefulHunter extends CardImpl { this.addAbility(ability); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private EllieVengefulHunter(final EllieVengefulHunter card) { diff --git a/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java b/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java index 7081587e355..3ba1e539a3a 100644 --- a/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java +++ b/Mage.Sets/src/mage/cards/e/ElusiveTormentor.java @@ -1,40 +1,66 @@ - package mage.cards.e; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.combat.CantBlockSourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.SuperType; + +import java.util.UUID; /** * @author fireshoes */ -public final class ElusiveTormentor extends CardImpl { +public final class ElusiveTormentor extends TransformingDoubleFacedCard { public ElusiveTormentor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.WIZARD}, "{2}{B}{B}", + "Insidious Mist", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL}, "U" + ); - this.secondSideCardClazz = mage.cards.i.InsidiousMist.class; + // Elusive Tormentor + this.getLeftHalfCard().setPT(4, 4); // {1}, Discard a card: Transform Elusive Tormentor. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(1)); ability.addCost(new DiscardCardCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + + // Insidious Mist + this.getRightHalfCard().setPT(0, 1); + + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Insidious Mist can't block and can't be blocked. + Ability staticAbility = new SimpleStaticAbility(new CantBlockSourceEffect(Duration.WhileOnBattlefield)); + staticAbility.addEffect(new CantBeBlockedSourceEffect().setText("and can't be blocked")); + this.getRightHalfCard().addAbility(staticAbility); + + // Whenever Insidious Mist attacks and isn't blocked, you may pay {2}{B}. If you do, transform it. + this.getRightHalfCard().addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid( + new TransformSourceEffect().setText("transform it"), new ManaCostsImpl<>("{2}{B}"), "Pay {2}{B} to transform?" + ))); } private ElusiveTormentor(final ElusiveTormentor card) { diff --git a/Mage.Sets/src/mage/cards/e/EmberBeast.java b/Mage.Sets/src/mage/cards/e/EmberBeast.java index c2f319d78d1..64067ef14a6 100644 --- a/Mage.Sets/src/mage/cards/e/EmberBeast.java +++ b/Mage.Sets/src/mage/cards/e/EmberBeast.java @@ -1,31 +1,29 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class EmberBeast extends CardImpl { public EmberBeast(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.BEAST); this.power = new MageInt(3); this.toughness = new MageInt(4); // Ember Beast can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private EmberBeast(final EmberBeast card) { diff --git a/Mage.Sets/src/mage/cards/e/EmberIslandProduction.java b/Mage.Sets/src/mage/cards/e/EmberIslandProduction.java new file mode 100644 index 00000000000..6c5c00c99d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmberIslandProduction.java @@ -0,0 +1,55 @@ +package mage.cards.e; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmberIslandProduction extends CardImpl { + + public EmberIslandProduction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); + + // Choose one-- + // * Create a token that's a copy of target creature you control, except it's not legendary and it's a 4/4 Hero in addition to its other types. + this.getSpellAbility().addEffect( + new CreateTokenCopyTargetEffect() + .setIsntLegendary(true) + .setPower(4) + .setToughness(4) + .withAdditionalSubType(SubType.HERO) + .setText("create a token that's a copy of target creature you control, " + + "except it's not legendary and it's a 4/4 Hero in addition to its other types") + ); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + + // * Create a token that's a copy of target creature an opponent controls, except it's not legendary and it's a 2/2 Coward in addition to its other types. + this.getSpellAbility().addMode(new Mode( + new CreateTokenCopyTargetEffect() + .setIsntLegendary(true) + .setPower(2) + .setToughness(2) + .withAdditionalSubType(SubType.COWARD) + .setText("create a token that's a copy of target creature an opponent controls, " + + "except it's not legendary and it's a 2/2 Coward in addition to its other types") + ).addTarget(new TargetOpponentsCreaturePermanent())); + } + + private EmberIslandProduction(final EmberIslandProduction card) { + super(card); + } + + @Override + public EmberIslandProduction copy() { + return new EmberIslandProduction(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmbodimentOfFlame.java b/Mage.Sets/src/mage/cards/e/EmbodimentOfFlame.java deleted file mode 100644 index c98e0c8cdb0..00000000000 --- a/Mage.Sets/src/mage/cards/e/EmbodimentOfFlame.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.e; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SpellControlledDealsDamageTriggeredAbility; -import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; -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.constants.Zone; -import mage.counters.CounterType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EmbodimentOfFlame extends CardImpl { - - public EmbodimentOfFlame(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Whenever a spell you control deals damage, put a flame counter on Embodiment of Flame. - this.addAbility(new SpellControlledDealsDamageTriggeredAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.FLAME.createInstance()), - StaticFilters.FILTER_SPELL, false - )); - - // {1}, Remove a flame counter from Embodiment of Flame: Exile the top card of your library. You may play that card this turn. - Ability ability = new SimpleActivatedAbility( - new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), - new GenericManaCost(1) - ); - ability.addCost(new RemoveCountersSourceCost(CounterType.FLAME.createInstance())); - this.addAbility(ability); - } - - private EmbodimentOfFlame(final EmbodimentOfFlame card) { - super(card); - } - - @Override - public EmbodimentOfFlame copy() { - return new EmbodimentOfFlame(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java b/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java index c2f8e872ee5..6d688e4d04e 100644 --- a/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java +++ b/Mage.Sets/src/mage/cards/e/EmetSelchUnsundered.java @@ -1,48 +1,66 @@ package mage.cards.e; -import java.util.UUID; -import mage.MageInt; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; /** * @author balazskristof */ -public final class EmetSelchUnsundered extends CardImpl { +public final class EmetSelchUnsundered extends TransformingDoubleFacedCard { public EmetSelchUnsundered(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.WIZARD}, "{1}{U}{B}", + "Hades, Sorcerer of Eld", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "" + ); - this.secondSideCardClazz = mage.cards.h.HadesSorcererOfEld.class; + // Emet-Selch, Unsundered + this.getLeftHalfCard().setPT(2, 4); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Whenever Emet-Selch enters or attacks, draw a card, then discard a card. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); // At the beginning of your upkeep, if there are fourteen or more cards in your graveyard, you may transform Emet-Selch. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( new TransformSourceEffect(), true - ).withInterveningIf(new CardsInControllerGraveyardCondition(14))); - this.addAbility(new TransformAbility()); + ).withInterveningIf(new CardsInControllerGraveyardCondition(14))); // assumption: condition counts all cards + + // Hades, Sorcerer of Eld + this.getRightHalfCard().setPT(6, 6); + this.getRightHalfCard().getColor().setBlue(true); + this.getRightHalfCard().getColor().setBlack(true); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Echo of the Lost -- During your turn, you may play cards from your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + PlayFromGraveyardControllerEffect.playCards(), MyTurnCondition.instance + ).setText("during your turn, you may play cards from your graveyard")).withFlavorWord("Echo of the Lost")); + + // If a card or token would be put into your graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true))); } private EmetSelchUnsundered(final EmetSelchUnsundered card) { diff --git a/Mage.Sets/src/mage/cards/e/Emptiness.java b/Mage.Sets/src/mage/cards/e/Emptiness.java index 747a3495a2f..f84c4bca8cd 100644 --- a/Mage.Sets/src/mage/cards/e/Emptiness.java +++ b/Mage.Sets/src/mage/cards/e/Emptiness.java @@ -48,7 +48,7 @@ public final class Emptiness extends CardImpl { this.addAbility(ability); // When this creature enters, if {B}{B} was spent to cast it, put three -1/-1 counters on up to one target creature. - ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(2))) + ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(3))) .withInterveningIf(TwoOfManaColorSpentCondition.BLACK); ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EnduringAngel.java b/Mage.Sets/src/mage/cards/e/EnduringAngel.java index cb4b85471a4..379bbc3b553 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringAngel.java +++ b/Mage.Sets/src/mage/cards/e/EnduringAngel.java @@ -1,20 +1,19 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.TransformAbility; -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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -25,28 +24,48 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EnduringAngel extends CardImpl { +public final class EnduringAngel extends TransformingDoubleFacedCard { public EnduringAngel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{2}{W}{W}{W}", + "Angelic Enforcer", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "W" + ); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AngelicEnforcer.class; + // Enduring Angel + this.getLeftHalfCard().setPT(3, 3); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Double strike - this.addAbility(DoubleStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(DoubleStrikeAbility.getInstance()); // You have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); // If your life total would be reduced to 0 or less, instead transform Enduring Angel and your life total becomes 3. Then if Enduring Angel didn't transform this way, you lose the game. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleStaticAbility(new EnduringAngelEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new EnduringAngelEffect())); + + // Angelic Enforcer + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // You have hexproof. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); + + // Angelic Enforcer's power and toughness are each equal to your life total. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect( + ControllerLifeCount.instance + ).setText("{this}'s power and toughness are each equal to your life total"))); + + // Whenever Angelic Enforcer attacks, double your life total. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new GainLifeEffect( + ControllerLifeCount.instance + ).setText("double your life total"))); } private EnduringAngel(final EnduringAngel card) { diff --git a/Mage.Sets/src/mage/cards/e/EnergyField.java b/Mage.Sets/src/mage/cards/e/EnergyField.java index 22955540fbd..d3e3ec3dfb7 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyField.java +++ b/Mage.Sets/src/mage/cards/e/EnergyField.java @@ -10,12 +10,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import java.util.Objects; import java.util.UUID; @@ -58,18 +54,6 @@ class EnergyFieldEffect extends PreventionEffectImpl { super(effect); } - @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 damage = event.getAmount(); - event.setAmount(0); - game.informPlayers("Damage has been prevented: " + damage); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER) { diff --git a/Mage.Sets/src/mage/cards/e/Energybending.java b/Mage.Sets/src/mage/cards/e/Energybending.java new file mode 100644 index 00000000000..af92484b839 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Energybending.java @@ -0,0 +1,39 @@ +package mage.cards.e; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BecomesAllBasicsControlledEffect; +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 Energybending extends CardImpl { + + public Energybending(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}"); + + this.subtype.add(SubType.LESSON); + + // Lands you control gain all basic land types until end of turn. + this.getSpellAbility().addEffect(new BecomesAllBasicsControlledEffect(Duration.EndOfTurn) + .setText("lands you control gain all basic land types until end of turn")); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private Energybending(final Energybending card) { + super(card); + } + + @Override + public Energybending copy() { + return new Energybending(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnterTheAvatarState.java b/Mage.Sets/src/mage/cards/e/EnterTheAvatarState.java new file mode 100644 index 00000000000..552e117162c --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnterTheAvatarState.java @@ -0,0 +1,46 @@ +package mage.cards.e; + +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HexproofAbility; +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.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnterTheAvatarState extends CardImpl { + + public EnterTheAvatarState(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + this.subtype.add(SubType.LESSON); + + // Until end of turn, target creature you control becomes an Avatar in addition to its other types and gains flying, first strike, lifelink, and hexproof. + this.getSpellAbility().addEffect(new AddCardSubTypeTargetEffect(SubType.AVATAR, Duration.EndOfTurn) + .setText("until end of turn, target creature you control becomes an Avatar in addition to its other types")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()).setText("and gains flying")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()).setText(", first strike")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(LifelinkAbility.getInstance()).setText(", lifelink")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance()).setText(", and hexproof")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private EnterTheAvatarState(final EnterTheAvatarState card) { + super(card); + } + + @Override + public EnterTheAvatarState copy() { + return new EnterTheAvatarState(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EpharaEverSheltering.java b/Mage.Sets/src/mage/cards/e/EpharaEverSheltering.java deleted file mode 100644 index 24431e2dee6..00000000000 --- a/Mage.Sets/src/mage/cards/e/EpharaEverSheltering.java +++ /dev/null @@ -1,81 +0,0 @@ -package mage.cards.e; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -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.filter.FilterPermanent; -import mage.filter.common.FilterControlledEnchantmentPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EpharaEverSheltering extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent("another enchantment"); - - static { - filter.add(AnotherPredicate.instance); - } - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - filter, ComparisonType.MORE_THAN, 2, true - ); - private static final Hint hint = new ValueHint( - "Other enchantments you control", new PermanentsOnBattlefieldCount(filter) - ); - - public EpharaEverSheltering(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Ephara, Ever-Sheltering has lifelink and indestructible as long as you control at least three other enchantments. - Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( - new GainAbilitySourceEffect(LifelinkAbility.getInstance()), - condition, "{this} has lifelink" - )); - ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( - IndestructibleAbility.getInstance()), condition, - "and indestructible as long as you control at least three other enchantments" - )); - this.addAbility(ability.addHint(hint)); - - // Whenever another enchantment you control enters, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new DrawCardSourceControllerEffect(1), filter)); - } - - private EpharaEverSheltering(final EpharaEverSheltering card) { - super(card); - } - - @Override - public EpharaEverSheltering copy() { - return new EpharaEverSheltering(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java b/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java index d7a5761a94e..a6c4a031f53 100644 --- a/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java +++ b/Mage.Sets/src/mage/cards/e/EraOfEnlightenment.java @@ -4,40 +4,46 @@ import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; +import mage.constants.SuperType; import java.util.UUID; /** * @author TheElk801 */ -public final class EraOfEnlightenment extends CardImpl { +public final class EraOfEnlightenment extends TransformingDoubleFacedCard { public EraOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{W}", + "Hand of Enlightenment", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "W" + ); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.h.HandOfEnlightenment.class; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + // Era of Enlightenment + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Scry 2. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new ScryEffect(2)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new ScryEffect(2)); // II — You gain 2 life. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainLifeEffect(2)); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new GainLifeEffect(2)); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Hand of Enlightenment + this.getRightHalfCard().setPT(2, 2); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); } private EraOfEnlightenment(final EraOfEnlightenment card) { diff --git a/Mage.Sets/src/mage/cards/e/EruptingDreadwolf.java b/Mage.Sets/src/mage/cards/e/EruptingDreadwolf.java deleted file mode 100644 index b713976e65f..00000000000 --- a/Mage.Sets/src/mage/cards/e/EruptingDreadwolf.java +++ /dev/null @@ -1,45 +0,0 @@ - -package mage.cards.e; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.common.TargetAnyTarget; - -/** - * - * @author fireshoes - */ -public final class EruptingDreadwolf extends CardImpl { - - public EruptingDreadwolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever Erupting Dreadwolf attacks, it deals 2 damage to any target. - Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(2, "it"), false); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - } - - private EruptingDreadwolf(final EruptingDreadwolf card) { - super(card); - } - - @Override - public EruptingDreadwolf copy() { - return new EruptingDreadwolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EsperOrigins.java b/Mage.Sets/src/mage/cards/e/EsperOrigins.java index 92025c053fb..e8c10f40d11 100644 --- a/Mage.Sets/src/mage/cards/e/EsperOrigins.java +++ b/Mage.Sets/src/mage/cards/e/EsperOrigins.java @@ -1,21 +1,27 @@ package mage.cards.e; +import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; import mage.abilities.condition.common.CastFromGraveyardSourceCondition; import mage.abilities.costs.mana.ManaCostsImpl; 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.effects.keyword.SurveilEffect; +import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.keyword.FlashbackAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TransformAbility; 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.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; import mage.counters.Counters; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -25,20 +31,48 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EsperOrigins extends CardImpl { +public final class EsperOrigins extends TransformingDoubleFacedCard { public EsperOrigins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); - this.secondSideCardClazz = mage.cards.s.SummonEsperMaduin.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.SORCERY}, new SubType[]{}, "{1}{G}", + "Summon: Esper Maduin", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.ELEMENTAL}, "G" + ); + // Esper Origins // Surveil 2. You gain 2 life. If this spell was cast from a graveyard, exile it, then put it onto the battlefield transformed under its owner's control with a finality counter on it. - this.getSpellAbility().addEffect(new SurveilEffect(2, false)); - this.getSpellAbility().addEffect(new GainLifeEffect(2)); - this.getSpellAbility().addEffect(new EsperOriginsEffect()); - this.addAbility(new TransformAbility()); + this.getLeftHalfCard().getSpellAbility().addEffect(new SurveilEffect(2, false)); + this.getLeftHalfCard().getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getLeftHalfCard().getSpellAbility().addEffect(new EsperOriginsEffect()); // Flashback {3}{G} - this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{3}{G}"))); + this.getLeftHalfCard().addAbility(new FlashbackAbility(this.getLeftHalfCard(), new ManaCostsImpl<>("{3}{G}"))); + + // Summon: Esper Maduin + this.getRightHalfCard().setPT(4, 4); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Reveal the top card of your library. If it's a permanent card, put it into your hand. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new SummonEsperMaduinEffect()); + + // II -- Add {G}{G}. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, new BasicManaEffect(Mana.GreenMana(2))); + + // III -- Other creatures you control get +2/+2 and gain trample until end of turn. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new BoostControlledEffect( + 2, 2, Duration.EndOfTurn, true + ).setText("other creatures you control get +2/+2"), + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and gain trample until end of turn") + ); + this.getRightHalfCard().addAbility(sagaAbility.withShowSacText(true)); } private EsperOrigins(final EsperOrigins card) { @@ -89,3 +123,37 @@ class EsperOriginsEffect extends OneShotEffect { return true; } } + +class SummonEsperMaduinEffect extends OneShotEffect { + + SummonEsperMaduinEffect() { + super(Outcome.Benefit); + staticText = "reveal the top card of your library. If it's a permanent card, put it into your hand"; + } + + private SummonEsperMaduinEffect(final SummonEsperMaduinEffect effect) { + super(effect); + } + + @Override + public SummonEsperMaduinEffect copy() { + return new SummonEsperMaduinEffect(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.revealCards(source, new CardsImpl(card), game); + if (card.isPermanent(game)) { + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EsperTerra.java b/Mage.Sets/src/mage/cards/e/EsperTerra.java deleted file mode 100644 index fd4cde6c0f4..00000000000 --- a/Mage.Sets/src/mage/cards/e/EsperTerra.java +++ /dev/null @@ -1,125 +0,0 @@ -package mage.cards.e; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledEnchantmentPermanent; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EsperTerra extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent("nonlegendary enchantment you control"); - - static { - filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); - } - - public EsperTerra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.nightCard = true; - this.color.setRed(true); - this.color.setGreen(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_IV); - - // I, II, III -- Create a token that's a copy of target nonlegendary enchantment you control. It gains haste. If it's a Saga, put up to three lore counters on it. Sacrifice it at the beginning of your next end step. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, - new EsperTerraEffect(), new TargetPermanent(filter) - ); - - // IV -- Add {W}{W}, {U}{U}, {B}{B}, {R}{R}, and {G}{G}. Exile Esper Terra, then return it to the battlefield. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_IV, - new BasicManaEffect(new Mana( - 2, 2, 2, 2, 2, 0, 0, 0 - )).setText("add {W}{W}, {U}{U}, {B}{B}, {R}{R}, and {G}{G}"), - new ExileSourceAndReturnFaceUpEffect()); - this.addAbility(sagaAbility); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private EsperTerra(final EsperTerra card) { - super(card); - } - - @Override - public EsperTerra copy() { - return new EsperTerra(this); - } -} - -class EsperTerraEffect extends OneShotEffect { - - EsperTerraEffect() { - super(Outcome.Benefit); - staticText = "create a token that's a copy of target nonlegendary enchantment you control. " + - "It gains haste. If it's a Saga, put up to three lore counters on it. " + - "Sacrifice it at the beginning of your next end step"; - } - - private EsperTerraEffect(final EsperTerraEffect effect) { - super(effect); - } - - @Override - public EsperTerraEffect copy() { - return new EsperTerraEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); - effect.setSavedPermanent(permanent); - effect.addAdditionalAbilities(HasteAbility.getInstance()); - effect.apply(game, source); - for (Permanent token : effect.getAddedPermanents()) { - if (!token.hasSubtype(SubType.SAGA, game)) { - continue; - } - Optional.ofNullable(source.getControllerId()) - .map(game::getPlayer) - .map(player -> player.getAmount( - 0, 3, "Choose how many lore counters to put on " + token.getIdName(), source, game - )) - .filter(amount -> amount > 0) - .ifPresent(amount -> token.addCounters(CounterType.LORE.createInstance(amount), source, game)); - } - effect.removeTokensCreatedAt(game, source, false, PhaseStep.END_TURN, TargetController.YOU); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/e/EsquireOfTheKing.java b/Mage.Sets/src/mage/cards/e/EsquireOfTheKing.java index 86d81519f8d..4c0c1812a77 100644 --- a/Mage.Sets/src/mage/cards/e/EsquireOfTheKing.java +++ b/Mage.Sets/src/mage/cards/e/EsquireOfTheKing.java @@ -3,14 +3,12 @@ package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -27,11 +25,6 @@ import java.util.UUID; */ public final class EsquireOfTheKing extends CardImpl { - private static final Hint hint = new ConditionHint( - new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY), - "You control a legendary creature" - ); - public EsquireOfTheKing(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); @@ -47,7 +40,7 @@ public final class EsquireOfTheKing extends CardImpl { ability.addCost(new TapSourceCost()); ability.setCostAdjuster(EsquireOfTheKingAdjuster.instance); ability.addEffect(new InfoEffect("This ability costs {2} less to activate if you control a legendary creature.")); - this.addAbility(ability.addHint(hint)); + this.addAbility(ability.addHint(YouControlALegendaryCreatureCondition.getHint())); } private EsquireOfTheKing(final EsquireOfTheKing card) { diff --git a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java index 5449a95c129..1117674c1c6 100644 --- a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java +++ b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java @@ -10,9 +10,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterEnchantmentCard; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.EnchantedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -28,11 +28,9 @@ import java.util.UUID; public final class EstridTheMasked extends CardImpl { private static final FilterPermanent filter = new FilterPermanent(); - private static final FilterPermanent filter2 = new FilterPermanent("another permanent"); static { filter.add(EnchantedPredicate.instance); - filter2.add(AnotherPredicate.instance); } public EstridTheMasked(UUID ownerId, CardSetInfo setInfo) { @@ -51,7 +49,7 @@ public final class EstridTheMasked extends CardImpl { Ability ability = new LoyaltyAbility( new EstridTheMaskedTokenEffect(), -1 ); - ability.addTarget(new TargetPermanent(filter2)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_PERMANENT)); this.addAbility(ability); // -7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards. diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java index 8330ea611f9..27d2adc26d8 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalConqueror.java @@ -1,16 +1,17 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; import mage.cards.*; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -21,27 +22,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class EtaliPrimalConqueror extends CardImpl { +public final class EtaliPrimalConqueror extends TransformingDoubleFacedCard { public EtaliPrimalConqueror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.DINOSAUR}, "{5}{R}{R}", + "Etali, Primal Sickness", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ELDER, SubType.DINOSAUR}, "RG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.secondSideCardClazz = mage.cards.e.EtaliPrimalSickness.class; + // Etali, Primal Conqueror + this.getLeftHalfCard().setPT(7, 7); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // When Etali, Primal Conqueror enters the battlefield, each player exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among the nonland cards exiled this way without paying their mana costs. - this.addAbility(new EntersBattlefieldTriggeredAbility(new EtaliPrimalConquerorEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new EtaliPrimalConquerorEffect())); // {9}{G/P}: Transform Etali. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{9}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{9}{G/P}"))); + + // Etali, Primal Sickness + this.getRightHalfCard().setPT(11, 11); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Whenever Etali, Primal Sickness deals combat damage to a player, they get that many poison counters. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new EtaliPrimalSicknessEffect(), false, true + )); } private EtaliPrimalConqueror(final EtaliPrimalConqueror card) { @@ -97,3 +111,27 @@ class EtaliPrimalConquerorEffect extends OneShotEffect { return true; } } + +class EtaliPrimalSicknessEffect extends OneShotEffect { + + EtaliPrimalSicknessEffect() { + super(Outcome.Benefit); + staticText = "they get that many poison counters"; + } + + private EtaliPrimalSicknessEffect(final EtaliPrimalSicknessEffect effect) { + super(effect); + } + + @Override + public EtaliPrimalSicknessEffect copy() { + return new EtaliPrimalSicknessEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + int damage = (Integer) getValue("damage"); + return player != null && player.addCounters(CounterType.POISON.createInstance(damage), source.getControllerId(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java deleted file mode 100644 index bc9f2c0fdaa..00000000000 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalSickness.java +++ /dev/null @@ -1,83 +0,0 @@ -package mage.cards.e; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.IndestructibleAbility; -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.constants.SuperType; -import mage.counters.CounterType; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class EtaliPrimalSickness extends CardImpl { - - public EtaliPrimalSickness(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(11); - this.toughness = new MageInt(11); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - - // Whenever Etali, Primal Sickness deals combat damage to a player, they get that many poison counters. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new EtaliPrimalSicknessEffect(), false, true - )); - } - - private EtaliPrimalSickness(final EtaliPrimalSickness card) { - super(card); - } - - @Override - public EtaliPrimalSickness copy() { - return new EtaliPrimalSickness(this); - } -} - -class EtaliPrimalSicknessEffect extends OneShotEffect { - - EtaliPrimalSicknessEffect() { - super(Outcome.Benefit); - staticText = "they get that many poison counters"; - } - - private EtaliPrimalSicknessEffect(final EtaliPrimalSicknessEffect effect) { - super(effect); - } - - @Override - public EtaliPrimalSicknessEffect copy() { - return new EtaliPrimalSicknessEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - int damage = (Integer) getValue("damage"); - return player.addCounters(CounterType.POISON.createInstance(damage), source.getControllerId(), source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java b/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java deleted file mode 100644 index 8e28b53447d..00000000000 --- a/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java +++ /dev/null @@ -1,88 +0,0 @@ -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 { - - 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/EvelynTheCovetous.java b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java index 5f098d88de5..bb54bf9003e 100644 --- a/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java +++ b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java @@ -174,8 +174,8 @@ class EvelynTheCovetousManaEffect extends AsThoughEffectImpl implements AsThough && EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0); } CardState cardState; - if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java b/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java index 4a941ceec6a..0c378675dfb 100644 --- a/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java +++ b/Mage.Sets/src/mage/cards/e/ExdeathVoidWarlock.java @@ -1,18 +1,20 @@ package mage.cards.e; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -23,31 +25,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ExdeathVoidWarlock extends CardImpl { +public final class ExdeathVoidWarlock extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(6, StaticFilters.FILTER_CARD_PERMANENTS); private static final Hint hint = new ValueHint( "Permanent cards in your graveyard", new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENT) ); + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENTS); public ExdeathVoidWarlock(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WARLOCK}, "{1}{B}{G}", + "Neo Exdeath, Dimension's End", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.AVATAR}, "BG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.n.NeoExdeathDimensionsEnd.class; + // Exdeath, Void Warlock + this.getLeftHalfCard().setPT(3, 3); // When Exdeath enters, you gain 3 life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); // At the beginning of your end step, if there are six or more permanent cards in your graveyard, transform Exdeath. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(hint)); + + // Neo Exdeath, Dimension's End + this.getRightHalfCard().setPT(0, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Neo Exdeath's power is equal to the number of permanent cards in your graveyard. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SetBasePowerSourceEffect(xValue))); } private ExdeathVoidWarlock(final ExdeathVoidWarlock card) { diff --git a/Mage.Sets/src/mage/cards/e/ExpansionExplosion.java b/Mage.Sets/src/mage/cards/e/ExpansionExplosion.java index 4c6fb4651f6..3115b588596 100644 --- a/Mage.Sets/src/mage/cards/e/ExpansionExplosion.java +++ b/Mage.Sets/src/mage/cards/e/ExpansionExplosion.java @@ -1,7 +1,6 @@ package mage.cards.e; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CopyTargetStackObjectEffect; @@ -82,7 +81,7 @@ class ExplosionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int xValue = CardUtil.getSourceCostsTag(game, source, "X", 0); - Effect effect = new DamageTargetEffect(StaticValue.get(xValue), true, "", true); + Effect effect = new DamageTargetEffect(xValue); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); effect.apply(game, source); Player player = game.getPlayer(source.getTargets().get(1).getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/ExperimentalLabStaffRoom.java b/Mage.Sets/src/mage/cards/e/ExperimentalLabStaffRoom.java new file mode 100644 index 00000000000..2c5783c44fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExperimentalLabStaffRoom.java @@ -0,0 +1,80 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExperimentalLabStaffRoom extends RoomCard { + + public ExperimentalLabStaffRoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{3}{G}", "{2}{G}"); + + // Experimental Lab + // When you unlock this door, manifest dread, then put two +1/+1 counters and a trample counter on that creature. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new ManifestDreadEffect( + CounterType.P1P1.createInstance(2), CounterType.TRAMPLE.createInstance() + ), false, true)); + + // Staff Room + // Whenever a creature you control deals combat damage to a player, turn that creature face up or put a +1/+1 counter on it. + this.getRightHalfCard().addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new StaffRoomEffect(), StaticFilters.FILTER_CONTROLLED_CREATURE, + false, SetTargetPointer.PERMANENT, true + )); + } + + private ExperimentalLabStaffRoom(final ExperimentalLabStaffRoom card) { + super(card); + } + + @Override + public ExperimentalLabStaffRoom copy() { + return new ExperimentalLabStaffRoom(this); + } +} + +class StaffRoomEffect extends OneShotEffect { + + StaffRoomEffect() { + super(Outcome.Benefit); + staticText = "turn that creature face up or put a +1/+1 counter on it"; + } + + private StaffRoomEffect(final StaffRoomEffect effect) { + super(effect); + } + + @Override + public StaffRoomEffect copy() { + return new StaffRoomEffect(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; + } + return permanent.isFaceDown(game) + && player.chooseUse(Outcome.BoostCreature, "Turn " + permanent.getIdName() + " creature face-up?", source, game) + && permanent.turnFaceUp(source, game, source.getControllerId()) + || permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java b/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java index a38deebd541..fd5faf51be3 100644 --- a/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java +++ b/Mage.Sets/src/mage/cards/e/ExplosiveWelcome.java @@ -1,8 +1,7 @@ package mage.cards.e; import mage.Mana; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,10 +10,8 @@ import mage.constants.ManaType; import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.other.AnotherTargetPredicate; -import mage.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetPermanentOrPlayer; -import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; @@ -23,7 +20,7 @@ import java.util.UUID; */ public final class ExplosiveWelcome extends CardImpl { - private static final FilterPermanentOrPlayer filter = new FilterAnyTarget(); + private static final FilterPermanentOrPlayer filter = new FilterAnyTarget("any other target"); static { filter.getPermanentFilter().add(new AnotherTargetPredicate(2)); @@ -34,19 +31,12 @@ public final class ExplosiveWelcome extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{7}{R}"); // Explosive Welcome deals 5 damage to any target and 3 damage to any other target. Add {R}{R}{R}. - this.getSpellAbility().addEffect(new DamageTargetEffect(StaticValue.get(5), true, "", true)); - this.getSpellAbility().addEffect( - new DamageTargetEffect(StaticValue.get(3), true, "", true) - .setTargetPointer(new SecondTargetPointer()) - .setText("and 3 damage to any other target.") - ); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(5, 3)); this.getSpellAbility().addEffect(new BasicManaEffect(new Mana(ManaType.RED, 3))); - Target target = new TargetAnyTarget(); - target.setTargetTag(1); - this.getSpellAbility().addTarget(target); - target = new TargetPermanentOrPlayer(filter); - target.setTargetTag(2); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addTarget(new TargetAnyTarget() + .withChooseHint("to deal 5 damage").setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter) + .withChooseHint("to deal 3 damage").setTargetTag(2)); } private ExplosiveWelcome(final ExplosiveWelcome card) { diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java deleted file mode 100644 index 1d9019bd1c1..00000000000 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfFlesh.java +++ /dev/null @@ -1,67 +0,0 @@ -package mage.cards.e; - -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.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.CreateTokenEffect; -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.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.game.permanent.token.EldraziHorrorToken; - -/** - * - * @author LevelX2 - */ -public final class ExtricatorOfFlesh extends CardImpl { - - private static final FilterControlledCreaturePermanent filterNonEldrazi = new FilterControlledCreaturePermanent("non-Eldrazi creature"); - private static final FilterControlledPermanent filterEldrazi = new FilterControlledPermanent(SubType.ELDRAZI, "Eldrazi"); - - static { - filterNonEldrazi.add(Predicates.not(SubType.ELDRAZI.getPredicate())); - } - - public ExtricatorOfFlesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Eldrazi you control have vigilance - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filterEldrazi))); - - // {2}, {T}, Sacrifice a non-Eldrazi creature: Create a 3/2 colorless Eldrazi Horror creature token. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new EldraziHorrorToken()), new GenericManaCost(2)); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(filterNonEldrazi)); - this.addAbility(ability); - } - - private ExtricatorOfFlesh(final ExtricatorOfFlesh card) { - super(card); - } - - @Override - public ExtricatorOfFlesh copy() { - return new ExtricatorOfFlesh(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java index e52dc72a2a3..d58ae932069 100644 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java +++ b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java @@ -1,21 +1,29 @@ package mage.cards.e; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.VigilanceAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.EldraziHorrorToken; @@ -24,33 +32,49 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class ExtricatorOfSin extends CardImpl { +public final class ExtricatorOfSin extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); + private static final FilterControlledCreaturePermanent filterNonEldrazi = new FilterControlledCreaturePermanent("non-Eldrazi creature"); + private static final FilterControlledPermanent filterEldrazi = new FilterControlledPermanent(SubType.ELDRAZI, "Eldrazi"); static { filter.add(AnotherPredicate.instance); + filterNonEldrazi.add(Predicates.not(SubType.ELDRAZI.getPredicate())); } public ExtricatorOfSin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(0); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{2}{W}", + "Extricator Of Flesh", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.HORROR}, "" + ); - this.secondSideCardClazz = mage.cards.e.ExtricatorOfFlesh.class; + // Extricator of Sin + this.getLeftHalfCard().setPT(0, 3); // When Extricator of Sin enters the battlefield, you may sacrifice another permanent. If you do, create a 3/2 colorless Eldrazi Horror creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new EldraziHorrorToken()), + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new EldraziHorrorToken()), new SacrificeTargetCost(filter)), false)); - // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, transform Extricator of Sin. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + // Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, transform Extricator of Sin. + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(DeliriumCondition.instance) .setAbilityWord(AbilityWord.DELIRIUM) .addHint(CardTypesInGraveyardCount.YOU.getHint())); + + // Extricator Of Flesh + this.getRightHalfCard().setPT(3, 5); + + // Eldrazi you control have vigilance + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filterEldrazi))); + + // {2}, {T}, Sacrifice a non-Eldrazi creature: Create a 3/2 colorless Eldrazi Horror creature token. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new EldraziHorrorToken()), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(filterNonEldrazi)); + this.getRightHalfCard().addAbility(ability); } private ExtricatorOfSin(final ExtricatorOfSin card) { diff --git a/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java b/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java index 775a3ded557..a5934e9a2ff 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfOjerTaq.java @@ -1,39 +1,71 @@ package mage.cards.e; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.choices.Choice; +import mage.choices.ChoiceCardType; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; 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.common.TargetCardInGraveyardBattlefieldOrStack; +import mage.util.CardUtil; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.*; +import java.util.stream.Collectors; /** - * * @author jeffwadsworth */ -public class EyeOfOjerTaq extends CardImpl { +public final class EyeOfOjerTaq extends TransformingDoubleFacedCard { public EyeOfOjerTaq(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - - this.secondSideCardClazz = mage.cards.a.ApexObservatory.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Apex Observatory", + new SuperType[]{}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "" + ); + // Eye of Ojer Taq // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); + this.getLeftHalfCard().addAbility(new AnyColorManaAbility()); - // Craft with two that share a card type {6} ({6}, Exile this artifact, Exile the two from among other permanents you control - // and/or cards from your graveyard: Return this card transformed under its owner’s control. Craft only as a sorcery.) - this.addAbility(new CraftAbility( + // Craft with two that share a card type {6} ({6}, Exile this artifact, Exile the two from among other permanents you control and/or cards from your graveyard: Return this card transformed under its owner's control. Craft only as a sorcery.) + this.getLeftHalfCard().addAbility(new CraftAbility( "{6}", "two that share a card type", new EyeOfOjerTaqTarget() )); + + // Apex Observatory + + // This artifact enters tapped. As it enters, choose a card type shared among two exiled cards used to craft it. + EntersBattlefieldEffect entersEffect = new EntersBattlefieldEffect(new TapSourceEffect(true) + .setText("{this} enters tapped")); + entersEffect.addEffect(new ChooseCardTypeEffect() + .concatBy("As it enters,")); + Ability observatoryAbility = new SimpleStaticAbility(entersEffect); + this.getRightHalfCard().addAbility(observatoryAbility); + + // The next spell you cast this turn of the chosen type can be cast without paying its mana cost. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost())); } private EyeOfOjerTaq(final EyeOfOjerTaq card) { @@ -44,20 +76,16 @@ public class EyeOfOjerTaq extends CardImpl { public EyeOfOjerTaq copy() { return new EyeOfOjerTaq(this); } - } class EyeOfOjerTaqTarget extends TargetCardInGraveyardBattlefieldOrStack { - private static final FilterCard filterCard - = new FilterCard(); - private static final FilterControlledPermanent filterPermanent - = new FilterControlledPermanent(); + private static final FilterCard filterCard = new FilterCard(); + private static final FilterControlledPermanent filterPermanent = new FilterControlledPermanent(); static { filterCard.add(TargetController.YOU.getOwnerPredicate()); filterPermanent.add(AnotherPredicate.instance); - } EyeOfOjerTaqTarget() { @@ -81,22 +109,204 @@ class EyeOfOjerTaqTarget extends TargetCardInGraveyardBattlefieldOrStack { Card cardObject = game.getCard(id); return cardObject != null && this.getTargets() - .stream() - .map(game::getCard) - .noneMatch(c -> sharesCardtype(cardObject, c, game)); + .stream() + .map(game::getCard) + .noneMatch(c -> sharesCardtype(cardObject, c, game)); } - + public static boolean sharesCardtype(Card card1, Card card2, Game game) { if (card1.getId().equals(card2.getId())) { return false; } - // this should be returned true, but the invert works. - // if you note the code logic issue, please speak up. for (CardType type : card1.getCardType(game)) { if (card2.getCardType(game).contains(type)) { - return false; + return false; // see comment in original code } } return true; } } + +class ChooseCardTypeEffect extends OneShotEffect { + + public ChooseCardTypeEffect() { + super(Outcome.Neutral); + staticText = "choose a card type shared among two exiled cards used to craft it."; + } + + protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + List exiledCardsCardType = new ArrayList<>(); + if (mageObject == null) { + mageObject = game.getObject(source); + } + if (controller != null && mageObject != null) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + ExileZone exileZone = game.getState() + .getExile() + .getExileZone(CardUtil + .getExileZoneId(game, permanent.getMainCard().getId(), permanent.getMainCard().getZoneChangeCounter(game))); + if (exileZone == null) { + return false; + } + for (Card card : exileZone.getCards(game)) { + exiledCardsCardType.addAll(card.getCardType(game)); + } + Choice cardTypeChoice = new ChoiceCardType(); + cardTypeChoice.getChoices().clear(); + cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList())); + Map cardTypeCounts = new HashMap<>(); + for (String cardType : cardTypeChoice.getChoices()) { + cardTypeCounts.put(cardType, 0); + } + for (Card c : exileZone.getCards(game)) { + for (CardType cardType : c.getCardType(game)) { + if (cardTypeCounts.containsKey(cardType.toString())) { + cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1); + } + } + } + List sharedCardTypes = new ArrayList<>(); + int numExiledCards = exileZone.getCards(game).size(); + for (Map.Entry entry : cardTypeCounts.entrySet()) { + if (entry.getValue() == numExiledCards) { + sharedCardTypes.add(entry.getKey()); + } + } + if (sharedCardTypes.isEmpty()) { + game.informPlayers(mageObject.getIdName() + " No exiled cards shared a type in exile, so nothing is done."); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("No exiled cards have the same card type."), game); + } + return false; + } + cardTypeChoice.getChoices().retainAll(sharedCardTypes); + if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) { + if (!game.isSimulation()) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice()); + } + game.getState().setValue("ApexObservatoryType_" + source.getSourceId().toString(), cardTypeChoice.getChoice()); + if (mageObject instanceof Permanent) { + ((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game); + } + return true; + } + } + return false; + } + + @Override + public ChooseCardTypeEffect copy() { + return new ChooseCardTypeEffect(this); + } +} + +class ApexObservatoryEffect extends OneShotEffect { + + ApexObservatoryEffect() { + super(Outcome.Benefit); + staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost."; + } + + private ApexObservatoryEffect(final ApexObservatoryEffect effect) { + super(effect); + } + + @Override + public ApexObservatoryEffect copy() { + return new ApexObservatoryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString()); + if (chosenCardType == null) { + return false; + } + game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source); + return true; + } +} + +class ApexObservatoryCastWithoutManaEffect extends ContinuousEffectImpl { + + class ApexObservatoryCondition implements Condition { + private final int spellCastCount; + + private ApexObservatoryCondition(int spellCastCount) { + this.spellCastCount = spellCastCount; + } + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (watcher != null) { + return watcher.getSpellsCastThisTurn(playerId).size() == spellCastCount; + } + return false; + } + } + + private final FilterCard filter; + private final String chosenCardType; + private final UUID playerId; + private int spellCastCount; + private AlternativeCostSourceAbility alternativeCostSourceAbility; + + ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) { + super(Duration.EndOfTurn, Layer.RulesEffects, SubLayer.NA, Outcome.PlayForFree); + this.chosenCardType = chosenCardType; + this.playerId = playerId; + this.filter = new FilterCard("spell of the chosen type"); + filter.add(CardType.fromString(chosenCardType).getPredicate()); + staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost"; + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (watcher != null) { + spellCastCount = watcher.getSpellsCastThisTurn(playerId).size(); + Condition condition = new ApexObservatoryCondition(spellCastCount); + alternativeCostSourceAbility = new AlternativeCostSourceAbility( + null, condition, null, filter, true + ); + } + } + + private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) { + super(effect); + this.chosenCardType = effect.chosenCardType; + this.playerId = effect.playerId; + this.used = effect.used; + this.spellCastCount = effect.spellCastCount; + this.filter = effect.filter; + this.alternativeCostSourceAbility = effect.alternativeCostSourceAbility; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(playerId); + if (controller == null) { + return false; + } + alternativeCostSourceAbility.setSourceId(source.getSourceId()); + controller.getAlternativeSourceCosts().add(alternativeCostSourceAbility); + return true; + } + + @Override + public ApexObservatoryCastWithoutManaEffect copy() { + return new ApexObservatoryCastWithoutManaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EzurisPredation.java b/Mage.Sets/src/mage/cards/e/EzurisPredation.java index dec66cf05f3..a478c3ce212 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisPredation.java +++ b/Mage.Sets/src/mage/cards/e/EzurisPredation.java @@ -92,7 +92,7 @@ class EzurisPredationEffect extends OneShotEffect { Permanent opponentCreature = creaturesOfOpponents.iterator().next(); creaturesOfOpponents.remove(opponentCreature); // can be multiple tokens, so must be used custom BATCH_FIGHT event - token.fight(opponentCreature, source, game, false); + token.fightWithExcess(opponentCreature, source, game, false); morSet.add(new MageObjectReference(token, game)); morSet.add(new MageObjectReference(opponentCreature, game)); game.informPlayers(token.getLogName() + " fights " + opponentCreature.getLogName()); diff --git a/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java b/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java index d2777c8eba9..a1eb74364d7 100644 --- a/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java +++ b/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java @@ -1,45 +1,74 @@ package mage.cards.f; +import mage.abilities.Ability; import mage.abilities.common.SagaAbility; +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.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.cards.TransformingDoubleFacedCard; +import mage.constants.*; +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.game.permanent.Permanent; import mage.game.permanent.token.FableOfTheMirrorBreakerToken; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author TheElk801 */ -public final class FableOfTheMirrorBreaker extends CardImpl { +public final class FableOfTheMirrorBreaker extends TransformingDoubleFacedCard { + + 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 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; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{R}", + "Reflection of Kiki-Jiki", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.GOBLIN, SubType.SHAMAN}, "R" + ); + // Fable of the Mirror-Breaker // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // 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())); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), 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) + sagaAbility.addChapterEffect(this.getLeftHalfCard(), 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Reflection of Kiki-Jiki + this.getRightHalfCard().setPT(2, 2); + + // {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.getRightHalfCard().addAbility(ability); } private FableOfTheMirrorBreaker(final FableOfTheMirrorBreaker card) { @@ -51,3 +80,35 @@ public final class FableOfTheMirrorBreaker extends CardImpl { return new FableOfTheMirrorBreaker(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) { + Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + if (permanent == null) { + return false; + } + + 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/f/FaithboundJudge.java b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java index 0098ae14971..1519ccd30ca 100644 --- a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java +++ b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java @@ -1,67 +1,83 @@ package mage.cards.f; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.*; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class FaithboundJudge extends CardImpl { +public final class FaithboundJudge extends TransformingDoubleFacedCard { private static final Condition condition1 = new SourceHasCounterCondition(CounterType.JUDGMENT, ComparisonType.OR_LESS, 2); private static final Condition condition2 = new SourceHasCounterCondition(CounterType.JUDGMENT, 3); public FaithboundJudge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "{1}{W}{W}", + "Sinner's Judgment", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "W"); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.s.SinnersJudgment.class; + this.getLeftHalfCard().setPT(4, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // At the beginning of your upkeep, if Faithbound Judge has two or fewer judgment counters on it, put a judgment counter on it. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance()) .setText("put a judgment counter on it"), false ).withInterveningIf(condition1)); // As long as Faithbound Judge has three or more judgment counters on it, it can attack as though it didn't have defender. - this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), condition2 ).setText("as long as {this} has three or more judgment counters on it, " + "it can attack as though it didn't have defender"))); - // Disturb {5}{W}{W} - this.addAbility(new DisturbAbility(this, "{5}{W}{W}")); + // Sinner's Judgement + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Faithbound Judge - Disturb {5}{W}{W} + // needs target from right half spell ability + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{5}{W}{W}")); + + // At the beginning of your upkeep, put a judgment counter on Sinner's Judgment. Then if there are three or more judgment counters on it, enchanted player loses the game. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance())); + ability.addEffect(new SinnersJudgmentEffect()); + this.getRightHalfCard().addAbility(ability); + + // If Sinner's Judgment would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private FaithboundJudge(final FaithboundJudge card) { @@ -73,3 +89,34 @@ public final class FaithboundJudge extends CardImpl { return new FaithboundJudge(this); } } + +class SinnersJudgmentEffect extends OneShotEffect { + + SinnersJudgmentEffect() { + super(Outcome.Benefit); + staticText = "Then if there are three or more judgment counters on it, enchanted player loses the game"; + } + + private SinnersJudgmentEffect(final SinnersJudgmentEffect effect) { + super(effect); + } + + @Override + public SinnersJudgmentEffect copy() { + return new SinnersJudgmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .filter(permanent -> permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3) + .map(Permanent::getAttachedTo) + .map(game::getPlayer) + .filter(player -> { + player.lost(game); + return true; + }) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java b/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java index dde1b9eb370..94171df03cb 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathPerforator.java @@ -24,9 +24,8 @@ public final class FalkenrathPerforator extends CardImpl { this.toughness = new MageInt(1); // Whenever Falkenrath Perforator attacks, it deals 1 damage to defending player. - this.addAbility(new AttacksTriggeredAbility(new DamageTargetEffect( - 1, true, "defending player", "it" - ), false, null, SetTargetPointer.PLAYER)); + this.addAbility(new AttacksTriggeredAbility(new DamageTargetEffect(1) + .withTargetDescription("defending player"), false, null, SetTargetPointer.PLAYER)); } private FalkenrathPerforator(final FalkenrathPerforator card) { diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java index 499d0a3a875..c59f26d3d0c 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java @@ -21,7 +21,8 @@ public final class FallOfTheTitans extends CardImpl { // Fall of the Titans deals X damage to each of up to two target creatures and/or players. this.getSpellAbility().addTarget(new TargetAnyTarget(0, 2)); - this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance, true, "each of up to two targets")); + this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance) + .withTargetDescription("each of up to two targets")); // Surge {X}{R} addAbility(new SurgeAbility(this, "{X}{R}")); diff --git a/Mage.Sets/src/mage/cards/f/FallersFaithful.java b/Mage.Sets/src/mage/cards/f/FallersFaithful.java index cfbb5d93758..077e46a5a9b 100644 --- a/Mage.Sets/src/mage/cards/f/FallersFaithful.java +++ b/Mage.Sets/src/mage/cards/f/FallersFaithful.java @@ -10,12 +10,11 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; -import java.util.Optional; import java.util.UUID; /** @@ -70,14 +69,14 @@ class FallersFaithfulEffect extends OneShotEffect { if (permanent == null) { return false; } - boolean flag = permanent.getDealtDamageByThisTurn().isEmpty(); + boolean notDamagedThisTurn = permanent.getDealtDamageByThisTurn().isEmpty(); permanent.destroy(source, game); - game.processAction(); - if (!flag) { - Optional.ofNullable(permanent) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .ifPresent(player -> player.drawCards(2, source, game)); + if (notDamagedThisTurn) { + game.processAction(); + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.drawCards(2, source, game); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/f/FancyFootwork.java b/Mage.Sets/src/mage/cards/f/FancyFootwork.java new file mode 100644 index 00000000000..45336365344 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FancyFootwork.java @@ -0,0 +1,37 @@ +package mage.cards.f; + +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.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FancyFootwork extends CardImpl { + + public FancyFootwork(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + this.subtype.add(SubType.LESSON); + + // Untap one or two target creatures. They each get +2/+2 until end of turn. + this.getSpellAbility().addEffect(new UntapTargetEffect()); + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2).setText("They each get +2/+2 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(1, 2)); + } + + private FancyFootwork(final FancyFootwork card) { + super(card); + } + + @Override + public FancyFootwork copy() { + return new FancyFootwork(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java b/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java new file mode 100644 index 00000000000..3773b60100a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FangRokusCompanion.java @@ -0,0 +1,130 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +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.UUID; + +/** + * @author TheElk801 + */ +public final class FangRokusCompanion extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target legendary creature you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public FangRokusCompanion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Fang attacks, another target legendary creature you control gets +X/+0 until end of turn, where X is Fang's power. + Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( + SourcePermanentPowerValue.NOT_NEGATIVE, StaticValue.get(0) + )); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // When Fang dies, if he wasn't a Spirit, return this card to the battlefield under your control. He's a Spirit in addition to his other types. + this.addAbility(new FangRokusCompanionTriggeredAbility()); + } + + private FangRokusCompanion(final FangRokusCompanion card) { + super(card); + } + + @Override + public FangRokusCompanion copy() { + return new FangRokusCompanion(this); + } +} + +class FangRokusCompanionTriggeredAbility extends DiesSourceTriggeredAbility { + + FangRokusCompanionTriggeredAbility() { + super(new FangRokusCompanionReturnEffect()); + } + + private FangRokusCompanionTriggeredAbility(final FangRokusCompanionTriggeredAbility ability) { + super(ability); + } + + @Override + public FangRokusCompanionTriggeredAbility copy() { + return new FangRokusCompanionTriggeredAbility(this); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return CardUtil + .getEffectValueFromAbility(this, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> !permanent.hasSubtype(SubType.SPIRIT, game)) + .isPresent(); + } +} + +class FangRokusCompanionReturnEffect extends OneShotEffect { + + FangRokusCompanionReturnEffect() { + super(Outcome.Benefit); + staticText = "if he wasn't a Spirit, return this card to the battlefield under your control. " + + "He's a Spirit in addition to his other types."; + } + + private FangRokusCompanionReturnEffect(final FangRokusCompanionReturnEffect effect) { + super(effect); + } + + @Override + public FangRokusCompanionReturnEffect copy() { + return new FangRokusCompanionReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (player == null || card == null) { + return false; + } + game.addEffect(new AddCardSubTypeTargetEffect(SubType.SPIRIT, Duration.Custom) + .setTargetPointer(new FixedTarget(new MageObjectReference(card, game, 1))), source); + return player.moveCards( + card, Zone.BATTLEFIELD, source, game, true, + false, true, null + ); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FangbladeBrigand.java b/Mage.Sets/src/mage/cards/f/FangbladeBrigand.java index e5f33e35fa3..4ed2b5a0af4 100644 --- a/Mage.Sets/src/mage/cards/f/FangbladeBrigand.java +++ b/Mage.Sets/src/mage/cards/f/FangbladeBrigand.java @@ -1,15 +1,16 @@ package mage.cards.f; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.FirstStrikeAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -19,16 +20,17 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class FangbladeBrigand extends CardImpl { +public final class FangbladeBrigand extends TransformingDoubleFacedCard { public FangbladeBrigand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Fangblade Eviscerator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.f.FangbladeEviscerator.class; + // Fangblade Brigand + this.getLeftHalfCard().setPT(3, 4); // {1}{R}: Fangblade Brigand gets +1/+0 and gains first strike until end of turn. Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( @@ -37,10 +39,30 @@ public final class FangbladeBrigand extends CardImpl { ability.addEffect(new GainAbilitySourceEffect( FirstStrikeAbility.getInstance(), Duration.EndOfTurn ).setText("and gains first strike until end of turn")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Fangblade Eviscerator + this.getRightHalfCard().setPT(4, 5); + + // {1}{R}: Fangblade Eviscerator gets +1/+0 and gains first strike until end of turn. + ability = new SimpleActivatedAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ).setText("{this} gets +1/+0"), new ManaCostsImpl<>("{1}{R}")); + ability.addEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); + this.getRightHalfCard().addAbility(ability); + + // {4}{R}: Creatures you control get +2/+0 until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new BoostControlledEffect( + 2, 0, Duration.EndOfTurn + ), new ManaCostsImpl<>("{4}{R}"))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private FangbladeBrigand(final FangbladeBrigand card) { diff --git a/Mage.Sets/src/mage/cards/f/FangbladeEviscerator.java b/Mage.Sets/src/mage/cards/f/FangbladeEviscerator.java deleted file mode 100644 index b9c7a4dabec..00000000000 --- a/Mage.Sets/src/mage/cards/f/FangbladeEviscerator.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.NightboundAbility; -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 FangbladeEviscerator extends CardImpl { - - public FangbladeEviscerator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.nightCard = true; - - // {1}{R}: Fangblade Eviscerator gets +1/+0 and gains first strike until end of turn. - Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( - 1, 0, Duration.EndOfTurn - ).setText("{this} gets +1/+0"), new ManaCostsImpl<>("{1}{R}")); - ability.addEffect(new GainAbilitySourceEffect( - FirstStrikeAbility.getInstance(), Duration.EndOfTurn - ).setText("and gains first strike until end of turn")); - this.addAbility(ability); - - // {4}{R}: Creatures you control get +2/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostControlledEffect( - 2, 0, Duration.EndOfTurn - ), new ManaCostsImpl<>("{4}{R}"))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private FangbladeEviscerator(final FangbladeEviscerator card) { - super(card); - } - - @Override - public FangbladeEviscerator copy() { - return new FangbladeEviscerator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FatalFissure.java b/Mage.Sets/src/mage/cards/f/FatalFissure.java new file mode 100644 index 00000000000..7078dea7373 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FatalFissure.java @@ -0,0 +1,40 @@ +package mage.cards.f; + +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.WhenTargetDiesDelayedTriggeredAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledLandPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FatalFissure extends CardImpl { + + public FatalFissure(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Choose target creature. When that creature dies this turn, you earthbend 4. + DelayedTriggeredAbility ability = new WhenTargetDiesDelayedTriggeredAbility(new EarthbendTargetEffect(4).setText("you earthbend 4")); + ability.addTarget(new TargetControlledLandPermanent()); + this.getSpellAbility().addEffect(new InfoEffect("choose target creature")); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(ability, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private FatalFissure(final FatalFissure card) { + super(card); + } + + @Override + public FatalFissure copy() { + return new FatalFissure(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FateUnraveler.java b/Mage.Sets/src/mage/cards/f/FateUnraveler.java index 991456c01c9..f278bc05a14 100644 --- a/Mage.Sets/src/mage/cards/f/FateUnraveler.java +++ b/Mage.Sets/src/mage/cards/f/FateUnraveler.java @@ -24,7 +24,7 @@ public final class FateUnraveler extends CardImpl { this.toughness = new MageInt(4); // Whenever an opponent draws a card, Fate Unraveler deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private FateUnraveler(final FateUnraveler card) { diff --git a/Mage.Sets/src/mage/cards/f/FatedClash.java b/Mage.Sets/src/mage/cards/f/FatedClash.java index 4d582e3651c..ebfd5bd0388 100644 --- a/Mage.Sets/src/mage/cards/f/FatedClash.java +++ b/Mage.Sets/src/mage/cards/f/FatedClash.java @@ -33,7 +33,7 @@ public final class FatedClash extends CardImpl { // You may cast this spell as though it had flash if a creature is attacking and a creature is blocking. this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( condition, "you may cast this spell as though it had flash " + - "if a creature is attacking and a creature is blocking" + "if a creature is attacking and a creature is blocking." )); // Target creature you control and target creature an opponent controls each gain indestructible until end of turn. Then destroy all creatures. diff --git a/Mage.Sets/src/mage/cards/f/FatefulEnd.java b/Mage.Sets/src/mage/cards/f/FatefulEnd.java index 4890a8f8415..cb22c7c62ad 100644 --- a/Mage.Sets/src/mage/cards/f/FatefulEnd.java +++ b/Mage.Sets/src/mage/cards/f/FatefulEnd.java @@ -18,7 +18,7 @@ public final class FatefulEnd extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Fateful End deals 3 damage to any target. Scry 1. - this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "any target")); + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new ScryEffect(1, false)); } diff --git a/Mage.Sets/src/mage/cards/f/FearFireFoes.java b/Mage.Sets/src/mage/cards/f/FearFireFoes.java index 230a0c21a29..0e598e70321 100644 --- a/Mage.Sets/src/mage/cards/f/FearFireFoes.java +++ b/Mage.Sets/src/mage/cards/f/FearFireFoes.java @@ -34,7 +34,6 @@ public final class FearFireFoes extends CardImpl { this.getSpellAbility().addEffect(new DamageCantBePreventedEffect( Duration.EndOfTurn )); - this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance)); this.getSpellAbility().addEffect(new FearFireFoesEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -53,7 +52,8 @@ class FearFireFoesEffect extends OneShotEffect { FearFireFoesEffect() { super(Outcome.Benefit); - staticText = "and 1 damage to each other creature with the same controller"; + staticText = "{this} deals X damage to target creature " + + "and 1 damage to each other creature with the same controller"; } private FearFireFoesEffect(final FearFireFoesEffect effect) { @@ -67,6 +67,7 @@ class FearFireFoesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + new DamageTargetEffect(GetXValue.instance).apply(game, source); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/f/FearfulVillager.java b/Mage.Sets/src/mage/cards/f/FearfulVillager.java index 175c8feb31f..c54cbe8abbb 100644 --- a/Mage.Sets/src/mage/cards/f/FearfulVillager.java +++ b/Mage.Sets/src/mage/cards/f/FearfulVillager.java @@ -1,10 +1,10 @@ package mage.cards.f; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +13,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class FearfulVillager extends CardImpl { +public final class FearfulVillager extends TransformingDoubleFacedCard { public FearfulVillager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}", + "Fearsome Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.f.FearsomeWerewolf.class; + // Fearful Villager + this.getLeftHalfCard().setPT(2, 3); // Menace - this.addAbility(new MenaceAbility()); + this.getLeftHalfCard().addAbility(new MenaceAbility()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Fearsome Werewolf + this.getRightHalfCard().setPT(4, 3); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private FearfulVillager(final FearfulVillager card) { diff --git a/Mage.Sets/src/mage/cards/f/FearsomeWerewolf.java b/Mage.Sets/src/mage/cards/f/FearsomeWerewolf.java deleted file mode 100644 index 53a629eabc4..00000000000 --- a/Mage.Sets/src/mage/cards/f/FearsomeWerewolf.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.NightboundAbility; -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 FearsomeWerewolf extends CardImpl { - - public FearsomeWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private FearsomeWerewolf(final FearsomeWerewolf card) { - super(card); - } - - @Override - public FearsomeWerewolf copy() { - return new FearsomeWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FibrousEntangler.java b/Mage.Sets/src/mage/cards/f/FibrousEntangler.java deleted file mode 100644 index ac64f9a2e07..00000000000 --- a/Mage.Sets/src/mage/cards/f/FibrousEntangler.java +++ /dev/null @@ -1,50 +0,0 @@ - -package mage.cards.f; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; -import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; -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; - -/** - * - * @author LevelX2 - */ -public final class FibrousEntangler extends CardImpl { - - public FibrousEntangler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(6); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - // Fibrous Entangler must be blocked if able. - this.addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); - - // Fibrous Entangler can block an additional creature each combat. - this.addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect(Duration.WhileOnBattlefield, 1))); - } - - private FibrousEntangler(final FibrousEntangler card) { - super(card); - } - - @Override - public FibrousEntangler copy() { - return new FibrousEntangler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java b/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java index ad81f8376c0..157c2ec53b7 100644 --- a/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java +++ b/Mage.Sets/src/mage/cards/f/FieryAnnihilation.java @@ -36,14 +36,12 @@ public final class FieryAnnihilation extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Fiery Annihilation deals 5 damage to target creature. Exile up to one target Equipment attached to that creature. If that creature would die this turn, exile it instead. - this.getSpellAbility().addEffect(new DamageTargetEffect( - 5, true, "target creature", true - )); + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ExileTargetEffect() .setTargetPointer(new SecondTargetPointer()) .setText("exile up to one target Equipment attached to that creature")); this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter)); } diff --git a/Mage.Sets/src/mage/cards/f/FinalIteration.java b/Mage.Sets/src/mage/cards/f/FinalIteration.java deleted file mode 100644 index de5fab8d202..00000000000 --- a/Mage.Sets/src/mage/cards/f/FinalIteration.java +++ /dev/null @@ -1,70 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -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.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.game.permanent.token.HumanWizardToken; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class FinalIteration extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("Wizards"); - - static { - filter.add(SubType.WIZARD.getPredicate()); - } - - public FinalIteration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.INSECT); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Wizards you control get +2/+1 and have flying. - Ability ability = new SimpleStaticAbility(new BoostControlledEffect( - 2, 1, Duration.WhileOnBattlefield, filter, false - )); - ability.addEffect(new GainAbilityControlledEffect( - FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter - ).setText("and have flying")); - this.addAbility(ability); - - // Whenever you cast an instant or sorcery spell, create a 1/1 blue Human Wizard creature token. - this.addAbility(new SpellCastControllerTriggeredAbility( - new CreateTokenEffect(new HumanWizardToken()), - StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false - )); - } - - private FinalIteration(final FinalIteration card) { - super(card); - } - - @Override - public FinalIteration copy() { - return new FinalIteration(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java b/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java index f7258a53ac3..701183efdd5 100644 --- a/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java +++ b/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java @@ -1,7 +1,6 @@ package mage.cards.f; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -30,8 +29,7 @@ public final class FireAndBrimstone extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}{W}"); // Fire and Brimstone deals 4 damage to target player who attacked this turn and 4 damage to you. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addEffect(new DamageControllerEffect(4).setText("and 4 damage to you")); + this.getSpellAbility().addEffect(new DamageTargetAndYouEffect(4)); this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filter)); } diff --git a/Mage.Sets/src/mage/cards/f/FireLordAzula.java b/Mage.Sets/src/mage/cards/f/FireLordAzula.java new file mode 100644 index 00000000000..4ad6e69e5c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireLordAzula.java @@ -0,0 +1,50 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.common.SourceAttackingCondition; +import mage.abilities.effects.common.CopyStackObjectEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireLordAzula extends CardImpl { + + public FireLordAzula(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // Whenever you cast a spell while Fire Lord Azula is attacking, copy that spell. You may choose new targets for the copy. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CopyStackObjectEffect("that spell"), + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL + ).withTriggerCondition(SourceAttackingCondition.instance)); + } + + private FireLordAzula(final FireLordAzula card) { + super(card); + } + + @Override + public FireLordAzula copy() { + return new FireLordAzula(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireLordOzai.java b/Mage.Sets/src/mage/cards/f/FireLordOzai.java new file mode 100644 index 00000000000..d161173dff6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireLordOzai.java @@ -0,0 +1,197 @@ +package mage.cards.f; + +import mage.MageIdentifier; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +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.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetSacrifice; +import mage.target.targetpointer.FixedTargets; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class FireLordOzai extends CardImpl { + + public FireLordOzai(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Fire Lord Ozai attacks, you may sacrifice another creature. If you do, add an amount of {R} equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end. + this.addAbility(new AttacksTriggeredAbility(new FireLordOzaiSacrificeEffect())); + + // {6}: Exile the top card of each opponent's library. Until end of turn, you may play one of those cards without paying its mana cost. + this.addAbility(new SimpleActivatedAbility(new FireLordOzaiCastEffect(), new GenericManaCost(6)) + .setIdentifier(MageIdentifier.FireLordOzaiAlternateCast), new FireLordOzaiWatcher()); + } + + private FireLordOzai(final FireLordOzai card) { + super(card); + } + + @Override + public FireLordOzai copy() { + return new FireLordOzai(this); + } +} + +class FireLordOzaiSacrificeEffect extends OneShotEffect { + + FireLordOzaiSacrificeEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice another creature. If you do, add an amount of {R} " + + "equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end"; + } + + private FireLordOzaiSacrificeEffect(final FireLordOzaiSacrificeEffect effect) { + super(effect); + } + + @Override + public FireLordOzaiSacrificeEffect copy() { + return new FireLordOzaiSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetSacrifice target = new TargetSacrifice(0, 1, StaticFilters.FILTER_ANOTHER_CREATURE); + player.choose(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + int power = permanent.getPower().getValue(); + if (power > 0) { + player.getManaPool().addMana(Mana.RedMana(power), game, source, Duration.EndOfCombat); + } + return true; + } +} + +class FireLordOzaiCastEffect extends OneShotEffect { + + FireLordOzaiCastEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of each opponent's library. Until end of turn, " + + "you may play one of those cards without paying its mana cost"; + } + + private FireLordOzaiCastEffect(final FireLordOzaiCastEffect effect) { + super(effect); + } + + @Override + public FireLordOzaiCastEffect copy() { + return new FireLordOzaiCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Cards cards = new CardsImpl(); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Optional.ofNullable(playerId) + .map(game::getPlayer) + .map(Player::getLibrary) + .map(library -> library.getFromTop(game)) + .ifPresent(cards::add); + } + if (cards.isEmpty()) { + return false; + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + FireLordOzaiWatcher.storeCardInfo(cards, game, source); + return true; + } +} + +class FireLordOzaiWatcher extends Watcher { + + private static final class FireLordOzaiCondition implements Condition { + + private final UUID token; + + FireLordOzaiCondition(UUID token) { + this.token = token; + } + + @Override + public boolean apply(Game game, Ability source) { + return !game + .getState() + .getWatcher(FireLordOzaiWatcher.class) + .usedTokens + .contains(token); + } + } + + private final Set usedTokens = new HashSet<>(); + private final Map> tokenMap = new HashMap<>(); + + FireLordOzaiWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case SPELL_CAST: + case LAND_PLAYED: + if (event.hasApprovingIdentifier(MageIdentifier.FireLordOzaiAlternateCast)) { + Optional.ofNullable(tokenMap.get(event.getPlayerId())) + .map(map -> map.get(event.getTargetId())) + .ifPresent(usedTokens::add); + } + } + } + + @Override + public void reset() { + super.reset(); + usedTokens.clear(); + tokenMap.clear(); + } + + static void storeCardInfo(Cards cards, Game game, Ability source) { + FireLordOzaiWatcher watcher = game.getState().getWatcher(FireLordOzaiWatcher.class); + UUID token = UUID.randomUUID(); + watcher.tokenMap.computeIfAbsent(source.getControllerId(), x -> new HashMap<>()); + for (UUID cardId : cards) { + watcher.tokenMap.get(source.getControllerId()).put(cardId, token); + } + game.addEffect(new ConditionalAsThoughEffect(new PlayFromNotOwnHandZoneTargetEffect( + Zone.ALL, TargetController.YOU, Duration.EndOfTurn, true, false + ), new FireLordOzaiCondition(token)).setTargetPointer(new FixedTargets(cards, game)), source); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireLordSozin.java b/Mage.Sets/src/mage/cards/f/FireLordSozin.java deleted file mode 100644 index 5074b2310fa..00000000000 --- a/Mage.Sets/src/mage/cards/f/FireLordSozin.java +++ /dev/null @@ -1,158 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.keyword.FirebendingAbility; -import mage.abilities.keyword.MenaceAbility; -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.FilterCard; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.card.OwnerIdPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class FireLordSozin extends CardImpl { - - public FireLordSozin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Firebending 3 - this.addAbility(new FirebendingAbility(3)); - - // Whenever Fire Lord Sozin deals combat damage to a player, you may pay {X}. When you do, put any number of target creature cards with total mana value X or less from that player's graveyard onto the battlefield under your control. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new FireLordSozinEffect())); - } - - private FireLordSozin(final FireLordSozin card) { - super(card); - } - - @Override - public FireLordSozin copy() { - return new FireLordSozin(this); - } -} - -class FireLordSozinEffect extends OneShotEffect { - - FireLordSozinEffect() { - super(Outcome.Benefit); - staticText = "you may pay {X}. When you do, put any number of target creature cards with " + - "total mana value X or less from that player's graveyard onto the battlefield under your control"; - } - - private FireLordSozinEffect(final FireLordSozinEffect effect) { - super(effect); - } - - @Override - public FireLordSozinEffect copy() { - return new FireLordSozinEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - if (controller == null || !controller.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) { - return false; - } - int xValue = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source, true); - ManaCosts cost = new ManaCostsImpl<>("{X}"); - cost.add(new GenericManaCost(xValue)); - if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { - return false; - } - ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); - ability.addTarget(new FireLordSozinTarget((UUID) getValue("damagedPlayer"), xValue)); - game.fireReflexiveTriggeredAbility(ability, source); - return true; - } -} - -class FireLordSozinTarget extends TargetCardInGraveyard { - - private final int xValue; - - private static final FilterCard makeFilter(UUID ownerId, int xValue) { - FilterCard filter = new FilterCreatureCard("creature cards with total mana value " + xValue + " or less from that player's graveyard"); - filter.add(new OwnerIdPredicate(ownerId)); - return filter; - } - - FireLordSozinTarget(UUID ownerId, int xValue) { - super(0, Integer.MAX_VALUE, makeFilter(ownerId, xValue), false); - this.xValue = xValue; - } - - private FireLordSozinTarget(final FireLordSozinTarget target) { - super(target); - this.xValue = target.xValue; - } - - @Override - public FireLordSozinTarget copy() { - return new FireLordSozinTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - return super.canTarget(playerId, id, source, game) - && CardUtil.checkCanTargetTotalValueLimit(this.getTargets(), id, MageObject::getManaValue, xValue, game); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - return CardUtil.checkPossibleTargetsTotalValueLimit( - this.getTargets(), - super.possibleTargets(sourceControllerId, source, game), - MageObject::getManaValue, xValue, game - ); - } - - @Override - public String getMessage(Game game) { - // shows selected total - int selectedValue = this.getTargets().stream() - .map(game::getObject) - .filter(Objects::nonNull) - .mapToInt(MageObject::getManaValue) - .sum(); - return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FireNationCadets.java b/Mage.Sets/src/mage/cards/f/FireNationCadets.java new file mode 100644 index 00000000000..99fac01ed27 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationCadets.java @@ -0,0 +1,53 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirebendingAbility; +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 FireNationCadets extends CardImpl { + + public FireNationCadets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // This creature has firebending 2 as long as there's a Lesson card in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new FirebendingAbility(2)), LessonsInGraveCondition.ONE, + "{this} has firebending 2 as long as there's a Lesson card in your graveyard" + )).addHint(LessonsInGraveCondition.getHint())); + + // {2}: This creature gets +1/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(2) + )); + } + + private FireNationCadets(final FireNationCadets card) { + super(card); + } + + @Override + public FireNationCadets copy() { + return new FireNationCadets(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationOccupation.java b/Mage.Sets/src/mage/cards/f/FireNationOccupation.java new file mode 100644 index 00000000000..e3412910b9a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationOccupation.java @@ -0,0 +1,39 @@ +package mage.cards.f; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.common.OpponentsTurnCondition; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.SoldierFirebendingToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationOccupation extends CardImpl { + + public FireNationOccupation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + + // When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierFirebendingToken()))); + + // Whenever you cast a spell during an opponent's turn, create a 2/2 red Soldier creature token with firebending 1. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new SoldierFirebendingToken()), false + ).withTriggerCondition(OpponentsTurnCondition.instance)); + } + + private FireNationOccupation(final FireNationOccupation card) { + super(card); + } + + @Override + public FireNationOccupation copy() { + return new FireNationOccupation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationPalace.java b/Mage.Sets/src/mage/cards/f/FireNationPalace.java new file mode 100644 index 00000000000..e7aaee487fe --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationPalace.java @@ -0,0 +1,51 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.YouControlABasicLandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationPalace extends CardImpl { + + public FireNationPalace(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a basic land. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance) + .addHint(YouControlABasicLandCondition.getHint())); + + // {T}: Add {R}. + this.addAbility(new RedManaAbility()); + + // {1}{R}, {T}: Target creature you control gains firebending 4 until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect(new FirebendingAbility(4)), new ManaCostsImpl<>("{1}{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private FireNationPalace(final FireNationPalace card) { + super(card); + } + + @Override + public FireNationPalace copy() { + return new FireNationPalace(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationRaider.java b/Mage.Sets/src/mage/cards/f/FireNationRaider.java new file mode 100644 index 00000000000..eeb93a34232 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationRaider.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.RaidCondition; +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.ClueArtifactToken; +import mage.watchers.common.PlayerAttackedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationRaider extends CardImpl { + + public FireNationRaider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Raid -- When this creature enters, if you attacked this turn, create a Clue token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken())) + .withInterveningIf(RaidCondition.instance) + .setAbilityWord(AbilityWord.RAID) + .addHint(RaidHint.instance), new PlayerAttackedWatcher()); + } + + private FireNationRaider(final FireNationRaider card) { + super(card); + } + + @Override + public FireNationRaider copy() { + return new FireNationRaider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java b/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java new file mode 100644 index 00000000000..7ed0ca54ac0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationSalvagers.java @@ -0,0 +1,77 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationSalvagers extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creatures you control with counters on them"); + private static final FilterCard filter2 = new FilterCard("creature or Vehicle card from that player's graveyard"); + + static { + filter.add(CounterAnyPredicate.instance); + filter2.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public FireNationSalvagers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature enters, put a +1/+1 counter on target creature or Vehicle you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_VEHICLE)); + this.addAbility(ability); + + // Whenever one or more creatures you control with counters on them deal combat damage to a player, put target creature or Vehicle card from that player's graveyard onto the battlefield under your control. + ability = new OneOrMoreCombatDamagePlayerTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), SetTargetPointer.PLAYER, filter, false + ); + ability.addTarget(new TargetCardInGraveyard(filter2)); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true)); + this.addAbility(ability); + } + + private FireNationSalvagers(final FireNationSalvagers card) { + super(card); + } + + @Override + public FireNationSalvagers copy() { + return new FireNationSalvagers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationTurret.java b/Mage.Sets/src/mage/cards/f/FireNationTurret.java new file mode 100644 index 00000000000..5e66014bf20 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationTurret.java @@ -0,0 +1,61 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationTurret extends CardImpl { + + public FireNationTurret(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); + + // At the beginning of combat on your turn, up to one target creature gets +2/+0 and gains firebending 2 until end of turn. + Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(2, 0) + .setText("up to one target creature gets +2/+0")); + ability.addEffect(new GainAbilityTargetEffect(new FirebendingAbility(2)) + .setText("and gains firebending 2 until end of turn")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // {R}: Put a charge counter on this artifact. + this.addAbility(new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), new ManaCostsImpl<>("{R}") + )); + + // Remove fifty charge counters from this artifact: It deals 50 damage to any target. + ability = new SimpleActivatedAbility( + new DamageTargetEffect(50, "it"), + new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(50)) + .setText("remove fifty charge counters from {this}") + ); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private FireNationTurret(final FireNationTurret card) { + super(card); + } + + @Override + public FireNationTurret copy() { + return new FireNationTurret(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNationWarship.java b/Mage.Sets/src/mage/cards/f/FireNationWarship.java new file mode 100644 index 00000000000..0fa1ef2e2a4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNationWarship.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNationWarship extends CardImpl { + + public FireNationWarship(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(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When this Vehicle dies, create a Clue token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private FireNationWarship(final FireNationWarship card) { + super(card); + } + + @Override + public FireNationWarship copy() { + return new FireNationWarship(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FireNavyTrebuchet.java b/Mage.Sets/src/mage/cards/f/FireNavyTrebuchet.java new file mode 100644 index 00000000000..14384d8587e --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FireNavyTrebuchet.java @@ -0,0 +1,83 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.ReachAbility; +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.BallisticBoulder; +import mage.game.permanent.token.Token; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FireNavyTrebuchet extends CardImpl { + + public FireNavyTrebuchet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever you attack, create a 2/1 colorless Construct artifact creature token with flying named Ballistic Boulder that's tapped and attacking. Sacrifice that token at the beginning of the next end step. + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new FireNavyTrebuchetEffect(), 1)); + } + + private FireNavyTrebuchet(final FireNavyTrebuchet card) { + super(card); + } + + @Override + public FireNavyTrebuchet copy() { + return new FireNavyTrebuchet(this); + } +} + +class FireNavyTrebuchetEffect extends OneShotEffect { + + FireNavyTrebuchetEffect() { + super(Outcome.Benefit); + staticText = "create a 2/1 colorless Construct artifact creature token with flying named Ballistic Boulder " + + "that's tapped and attacking. Sacrifice that token at the beginning of the next end step."; + } + + private FireNavyTrebuchetEffect(final FireNavyTrebuchetEffect effect) { + super(effect); + } + + @Override + public FireNavyTrebuchetEffect copy() { + return new FireNavyTrebuchetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new BallisticBoulder(); + token.putOntoBattlefield(1, game, source, source.getControllerId(), true, true); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect() + .setTargetPointer(new FixedTargets(token, game)) + .setText("sacrifice those tokens") + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirebenderAscension.java b/Mage.Sets/src/mage/cards/f/FirebenderAscension.java new file mode 100644 index 00000000000..b0424bb3997 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FirebenderAscension.java @@ -0,0 +1,132 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.decorator.OptionalOneShotEffect; +import mage.abilities.effects.common.CopyStackObjectEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.DefenderAttackedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SoldierFirebendingToken; +import mage.game.stack.StackObject; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author Grath + */ +public final class FirebenderAscension extends CardImpl { + + public FirebenderAscension(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierFirebendingToken()))); + + // Whenever a creature you control attacking causes a triggered ability of that creature to trigger, put a quest + // counter on this enchantment. Then if it has four or more quest counters on it, you may copy that ability. You + // may choose new targets for the copy. + this.addAbility(new FirebenderAscensionTriggeredAbility()); + } + + private FirebenderAscension(final FirebenderAscension card) { + super(card); + } + + @Override + public FirebenderAscension copy() { + return new FirebenderAscension(this); + } +} + +class FirebenderAscensionTriggeredAbility extends TriggeredAbilityImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4); + + FirebenderAscensionTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance(), true), false); + addEffect(new ConditionalOneShotEffect(new OptionalOneShotEffect(new CopyStackObjectEffect()), condition, + "Then if it has four or more quest counters on it, you may copy that ability. You may choose new targets for the copy.")); + setTriggerPhrase("Whenever a creature you control attacking causes a triggered ability of that creature to trigger, "); + } + + private FirebenderAscensionTriggeredAbility(final FirebenderAscensionTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TRIGGERED_ABILITY; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); + Permanent permanent = game.getPermanent(event.getSourceId()); + if (stackObject == null || permanent == null || !permanent.isCreature(game)) { + return false; // only creatures + } + if (this.getControllerId() != permanent.getControllerId()) { + return false; // only your creatures + } + Ability stackAbility = stackObject.getStackAbility(); + if (!stackAbility.isTriggeredAbility()) { + return false; + } + GameEvent triggerEvent = ((TriggeredAbility) stackAbility).getTriggerEvent(); + GameEvent.EventType eventType = triggerEvent.getType(); + if (triggerEvent == null || (eventType != GameEvent.EventType.ATTACKER_DECLARED && + eventType != GameEvent.EventType.DECLARED_ATTACKERS && + eventType != GameEvent.EventType.DEFENDER_ATTACKED)) { + return false; // only attacking triggers + } + switch (triggerEvent.getType()) { + case ATTACKER_DECLARED: + if (triggerEvent.getSourceId() != permanent.getId()) { + return false; + } // only triggered abilities of that creature + break; + case DECLARED_ATTACKERS: + if (game + .getCombat() + .getAttackers() + .stream() + .noneMatch(permanent.getId()::equals)) { + return false; + } // only if the creature was one of the attackers that were declared + // This might give some false positives? + break; + case DEFENDER_ATTACKED: + if (((DefenderAttackedEvent) triggerEvent) + .getAttackers(game) + .stream() + .noneMatch(permanent::equals)) { + return false; + } // only if the creature was one of the attackers that were declared + // This might give some false positives? + } + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + return true; + } + + @Override + public FirebenderAscensionTriggeredAbility copy() { + return new FirebenderAscensionTriggeredAbility(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FirebendingLesson.java b/Mage.Sets/src/mage/cards/f/FirebendingLesson.java new file mode 100644 index 00000000000..495e9c46ab9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FirebendingLesson.java @@ -0,0 +1,45 @@ +package mage.cards.f; + +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.KickerAbility; +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 FirebendingLesson extends CardImpl { + + public FirebendingLesson(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + this.subtype.add(SubType.LESSON); + + // Kicker {4} + this.addAbility(new KickerAbility("{4}")); + + // Firebending Lesson deals 2 damage to target creature. If this spell was kicked, it deals 5 damage to that creature instead. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(5), new DamageTargetEffect(2), + KickedCondition.ONCE, "{this} deals 2 damage to target creature. " + + "If this spell was kicked, it deals 5 damage to that creature instead" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private FirebendingLesson(final FirebendingLesson card) { + super(card); + } + + @Override + public FirebendingLesson copy() { + return new FirebendingLesson(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirebendingStudent.java b/Mage.Sets/src/mage/cards/f/FirebendingStudent.java new file mode 100644 index 00000000000..a08eb6415e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FirebendingStudent.java @@ -0,0 +1,42 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.ProwessAbility; +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 FirebendingStudent extends CardImpl { + + public FirebendingStudent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Prowess + this.addAbility(new ProwessAbility()); + + // Firebending X, where X is this creature's power. + this.addAbility(new FirebendingAbility(SourcePermanentPowerValue.NOT_NEGATIVE)); + } + + private FirebendingStudent(final FirebendingStudent card) { + super(card); + } + + @Override + public FirebendingStudent copy() { + return new FirebendingStudent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/Fireslinger.java b/Mage.Sets/src/mage/cards/f/Fireslinger.java index d0312a29d12..92e78e6cb22 100644 --- a/Mage.Sets/src/mage/cards/f/Fireslinger.java +++ b/Mage.Sets/src/mage/cards/f/Fireslinger.java @@ -4,8 +4,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,8 +25,7 @@ public final class Fireslinger extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); - ability.addEffect(new DamageControllerEffect(1).setText("and 1 damage to you")); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(1), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/Firespout.java b/Mage.Sets/src/mage/cards/f/Firespout.java index c8ed77f2799..a992ca121da 100644 --- a/Mage.Sets/src/mage/cards/f/Firespout.java +++ b/Mage.Sets/src/mage/cards/f/Firespout.java @@ -1,17 +1,20 @@ - package mage.cards.f; +import mage.abilities.Ability; import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; 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 java.util.UUID; @@ -30,12 +33,8 @@ public final class Firespout extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R/G}"); // Firespout deals 3 damage to each creature without flying if {R} was spent to cast Firespout and 3 damage to each creature with flying if {G} was spent to cast it. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageAllEffect(3, filter1), - ManaWasSpentCondition.RED, "{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, StaticFilters.FILTER_CREATURE_FLYING), - ManaWasSpentCondition.GREEN, "and 3 damage to each creature with flying if {G} was spent to cast this spell. (Do both if {R}{G} was spent.)")); + this.getSpellAbility().addEffect(new FirespoutEffect()); + } private Firespout(final Firespout card) { @@ -47,3 +46,37 @@ public final class Firespout extends CardImpl { return new Firespout(this); } } + +// needed for simultaneous damage +class FirespoutEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + FirespoutEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 3 damage to each creature without flying if {R} was spent to cast this spell " + + "and 3 damage to each creature with flying if {G} was spent to cast this spell. " + + "(Do both if {R}{G} was spent.)"; + } + + private FirespoutEffect(final FirespoutEffect effect) { + super(effect); + } + + @Override + public FirespoutEffect copy() { + return new FirespoutEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new ConditionalOneShotEffect(new DamageAllEffect(3, filter), + ManaWasSpentCondition.RED).apply(game, source); + new ConditionalOneShotEffect(new DamageAllEffect(3, StaticFilters.FILTER_CREATURE_FLYING), + ManaWasSpentCondition.GREEN).apply(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirstTimeFlyer.java b/Mage.Sets/src/mage/cards/f/FirstTimeFlyer.java index 945c34d9b2b..fa877cfb032 100644 --- a/Mage.Sets/src/mage/cards/f/FirstTimeFlyer.java +++ b/Mage.Sets/src/mage/cards/f/FirstTimeFlyer.java @@ -2,19 +2,15 @@ package mage.cards.f; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.LessonsInGraveCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; 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.filter.FilterCard; import java.util.UUID; @@ -23,9 +19,6 @@ import java.util.UUID; */ public final class FirstTimeFlyer extends CardImpl { - private static final Condition condition = new CardsInControllerGraveyardCondition(1, new FilterCard(SubType.LESSON)); - private static final Hint hint = new ConditionHint(condition, "There's a Lesson card in your graveyard"); - public FirstTimeFlyer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); @@ -40,9 +33,9 @@ public final class FirstTimeFlyer extends CardImpl { // This creature gets +1/+1 as long as there's a Lesson card in your graveyard. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( - new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), - condition, "{this} gets +1/+1 as long as there's a Lesson card in your graveyard" - )).addHint(hint)); + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), LessonsInGraveCondition.ONE, + "{this} gets +1/+1 as long as there's a Lesson card in your graveyard" + )).addHint(LessonsInGraveCondition.getHint())); } private FirstTimeFlyer(final FirstTimeFlyer card) { diff --git a/Mage.Sets/src/mage/cards/f/FirstVolley.java b/Mage.Sets/src/mage/cards/f/FirstVolley.java index 8186188eeae..da125cec8a0 100644 --- a/Mage.Sets/src/mage/cards/f/FirstVolley.java +++ b/Mage.Sets/src/mage/cards/f/FirstVolley.java @@ -1,9 +1,6 @@ - package mage.cards.f; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,10 +20,7 @@ public final class FirstVolley extends CardImpl { this.subtype.add(SubType.ARCANE); // First Volley deals 1 damage to target creature and 1 damage to that creature's controller. - this.getSpellAbility().addEffect(new DamageTargetEffect(1)); - Effect effect = new DamageTargetControllerEffect(1); - effect.setText("and 1 damage to that creature's controller"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new DamageTargetAndTargetControllerEffect(1, 1)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/f/FishingGear.java b/Mage.Sets/src/mage/cards/f/FishingGear.java new file mode 100644 index 00000000000..7aabffb6528 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FishingGear.java @@ -0,0 +1,86 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +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.game.Game; +import mage.game.permanent.token.FishNoAbilityToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FishingGear extends CardImpl { + + public FishingGear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Whenever equipped creature deals combat damage to a player, exile the top card of that player's library. If it's a permanent card, you may put it onto the battlefield under your control. If you don't, create a 1/1 blue Fish creature token. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new FishingGearEffect(), "equipped", false, true, true + )); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private FishingGear(final FishingGear card) { + super(card); + } + + @Override + public FishingGear copy() { + return new FishingGear(this); + } +} + +class FishingGearEffect extends OneShotEffect { + + FishingGearEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of that player's library. " + + "If it's a permanent card, you may put it onto the battlefield under your control. " + + "If you don't, create a 1/1 blue Fish creature token"; + } + + private FishingGearEffect(final FishingGearEffect effect) { + super(effect); + } + + @Override + public FishingGearEffect copy() { + return new FishingGearEffect(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 = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + controller.moveCards(card, Zone.EXILED, source, game); + if (card.isPermanent(game) && controller.chooseUse(outcome, "Put it onto the battlefield?", source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { + new FishNoAbilityToken().putOntoBattlefield(1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlameChanneler.java b/Mage.Sets/src/mage/cards/f/FlameChanneler.java index 363d8c7c634..5f2e743ec30 100644 --- a/Mage.Sets/src/mage/cards/f/FlameChanneler.java +++ b/Mage.Sets/src/mage/cards/f/FlameChanneler.java @@ -1,14 +1,20 @@ package mage.cards.f; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellControlledDealsDamageTriggeredAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import mage.counters.CounterType; import mage.filter.StaticFilters; import java.util.UUID; @@ -16,22 +22,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class FlameChanneler extends CardImpl { +public final class FlameChanneler extends TransformingDoubleFacedCard { public FlameChanneler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{R}", + "Embodiment of Flame", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.WIZARD}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.e.EmbodimentOfFlame.class; + // Flame Channeler + this.getLeftHalfCard().setPT(2, 2); // When a spell you control deals damage, transform Flame Channeler. - this.addAbility(new TransformAbility()); - this.addAbility(new SpellControlledDealsDamageTriggeredAbility(Zone.BATTLEFIELD, + this.getLeftHalfCard().addAbility(new SpellControlledDealsDamageTriggeredAbility(Zone.BATTLEFIELD, new TransformSourceEffect(), StaticFilters.FILTER_SPELL, false ).setTriggerPhrase("When a spell you control deals damage, ")); + + // Embodiment of Flame + this.getRightHalfCard().setPT(3, 3); + + // Whenever a spell you control deals damage, put a flame counter on Embodiment of Flame. + this.getRightHalfCard().addAbility(new SpellControlledDealsDamageTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.FLAME.createInstance()), + StaticFilters.FILTER_SPELL, false + )); + + // {1}, Remove a flame counter from Embodiment of Flame: Exile the top card of your library. You may play that card this turn. + Ability ability = new SimpleActivatedAbility( + new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), + new GenericManaCost(1) + ); + ability.addCost(new RemoveCountersSourceCost(CounterType.FLAME.createInstance())); + this.getRightHalfCard().addAbility(ability); } private FlameChanneler(final FlameChanneler card) { diff --git a/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java b/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java index 2f7bc7c0015..be67527a492 100644 --- a/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java +++ b/Mage.Sets/src/mage/cards/f/FlamebladeAngel.java @@ -28,7 +28,7 @@ public final class FlamebladeAngel extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever a source an opponent controls deals damage to you or a permanent you control, you may have Flameblade Angel deal 1 damage to that source's controller. - Effect effect = new DamageTargetEffect(1, true, "that source's controller"); + Effect effect = new DamageTargetEffect(1).withTargetDescription("that source's controller"); this.addAbility(new SourceDealsDamageToYouTriggeredAbility(effect, StaticFilters.FILTER_PERMANENT, true)); } diff --git a/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java b/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java deleted file mode 100644 index a1666e46be1..00000000000 --- a/Mage.Sets/src/mage/cards/f/FlameheartWerewolf.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.common.BlocksOrBlockedByCreatureSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class FlameheartWerewolf extends CardImpl { - - public FlameheartWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever Flameheart Werewolf blocks or becomes blocked by a creature, Flameheart Werewolf deals 2 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(2, true, "that creature"))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Flameheart Werewolf. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private FlameheartWerewolf(final FlameheartWerewolf card) { - super(card); - } - - @Override - public FlameheartWerewolf copy() { - return new FlameheartWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java b/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java index ef55c8f7de0..8f03422d378 100644 --- a/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java +++ b/Mage.Sets/src/mage/cards/f/FlamesOfTheBloodHand.java @@ -24,7 +24,7 @@ public final class FlamesOfTheBloodHand extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Flames of the Blood Hand deals 4 damage to target player. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(4, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).withCantBePrevented()); // If that player would gain life this turn, that player gains no life instead. this.getSpellAbility().addEffect(new FlamesOfTheBloodHandReplacementEffect()); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); diff --git a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java index de0e113027a..2a3bfa4abb9 100644 --- a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java +++ b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java @@ -6,7 +6,6 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -73,7 +72,8 @@ public final class FlamescrollCelebrant extends ModalDoubleFacedCard { class FlamescrollCelebrantTriggeredAbility extends TriggeredAbilityImpl { FlamescrollCelebrantTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent activates an ability that isn't a mana ability, "); } private FlamescrollCelebrantTriggeredAbility(final FlamescrollCelebrantTriggeredAbility ability) { @@ -103,11 +103,6 @@ class FlamescrollCelebrantTriggeredAbility extends TriggeredAbilityImpl { return true; } - @Override - public String getRule() { - return "Whenever an opponent activates an ability that isn't a mana ability, " + - "{this} deals 1 damage to that player."; - } } class RevelInSilenceEffect extends ContinuousRuleModifyingEffectImpl { diff --git a/Mage.Sets/src/mage/cards/f/FlamewarBrashVeteran.java b/Mage.Sets/src/mage/cards/f/FlamewarBrashVeteran.java index 167a48fc486..345e693acc2 100644 --- a/Mage.Sets/src/mage/cards/f/FlamewarBrashVeteran.java +++ b/Mage.Sets/src/mage/cards/f/FlamewarBrashVeteran.java @@ -1,8 +1,8 @@ package mage.cards.f; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardHandCost; import mage.abilities.costs.common.SacrificeTargetCost; @@ -10,10 +10,11 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.LivingMetalAbility; +import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterControlledArtifactPermanent; @@ -29,7 +30,7 @@ import java.util.stream.Collectors; /** * @author TheElk801 */ -public final class FlamewarBrashVeteran extends CardImpl { +public final class FlamewarBrashVeteran extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledArtifactPermanent("another artifact"); @@ -39,28 +40,46 @@ public final class FlamewarBrashVeteran extends CardImpl { } public FlamewarBrashVeteran(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{B}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{1}{B}{R}", + "Flamewar, Streetwise Operative", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "BR" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.f.FlamewarStreetwiseOperative.class; + // Flamewar, Brash Veteran + this.getLeftHalfCard().setPT(3, 2); // More Than Meets the Eye {B}{R} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{B}{R}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{B}{R}")); // Sacrifice another artifact: Put a +1/+1 counter on Flamewar and convert it. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new SacrificeTargetCost(filter) ); ability.addEffect(new TransformSourceEffect().setText("and convert it")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {1}, Discard your hand: Put all exiled cards you own with intel counters on them into your hand. ability = new SimpleActivatedAbility(new FlamewarBrashVeteranEffect(), new GenericManaCost(1)); ability.addCost(new DiscardHandCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Flamewar, Streetwise Operative + this.getRightHalfCard().setPT(2, 1); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Flamewar deals combat damage to a player, exile that many cards from the top of your library face down. Put an intel counter on each of them. Convert Flamewar. + Ability backAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new FlamewarStreetwiseOperativeEffect(), false); + backAbility.addEffect(new TransformSourceEffect().setText("convert {this}")); + this.getRightHalfCard().addAbility(backAbility); } private FlamewarBrashVeteran(final FlamewarBrashVeteran card) { @@ -104,3 +123,38 @@ class FlamewarBrashVeteranEffect extends OneShotEffect { return !cards.isEmpty() && player.moveCards(cards, Zone.HAND, source, game); } } + +class FlamewarStreetwiseOperativeEffect extends OneShotEffect { + + FlamewarStreetwiseOperativeEffect() { + super(Outcome.Benefit); + staticText = "exile that many cards from the top of your library face down. " + + "Put an intel counter on each of them"; + } + + private FlamewarStreetwiseOperativeEffect(final FlamewarStreetwiseOperativeEffect effect) { + super(effect); + } + + @Override + public FlamewarStreetwiseOperativeEffect copy() { + return new FlamewarStreetwiseOperativeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + int damage = (Integer) getValue("damage"); + if (player == null || damage < 1) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, damage)); + player.moveCards(cards, Zone.EXILED, source, game); + cards.retainZone(Zone.EXILED, game); + cards.getCards(game).forEach(card -> { + card.setFaceDown(true, game); + card.addCounters(CounterType.INTEL.createInstance(), source, game); + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlamewarStreetwiseOperative.java b/Mage.Sets/src/mage/cards/f/FlamewarStreetwiseOperative.java deleted file mode 100644 index 6541885896a..00000000000 --- a/Mage.Sets/src/mage/cards/f/FlamewarStreetwiseOperative.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.abilities.keyword.MenaceAbility; -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.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class FlamewarStreetwiseOperative extends CardImpl { - - public FlamewarStreetwiseOperative(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setRed(true); - this.color.setBlack(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Flamewar deals combat damage to a player, exile that many cards from the top of your library face down. Put an intel counter on each of them. Convert Flamewar. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new FlamewarStreetwiseOperativeEffect(), false); - ability.addEffect(new TransformSourceEffect().setText("convert {this}")); - this.addAbility(ability); - } - - private FlamewarStreetwiseOperative(final FlamewarStreetwiseOperative card) { - super(card); - } - - @Override - public FlamewarStreetwiseOperative copy() { - return new FlamewarStreetwiseOperative(this); - } -} - -class FlamewarStreetwiseOperativeEffect extends OneShotEffect { - - FlamewarStreetwiseOperativeEffect() { - super(Outcome.Benefit); - staticText = "exile that many cards from the top of your library face down. " + - "Put an intel counter on each of them"; - } - - private FlamewarStreetwiseOperativeEffect(final FlamewarStreetwiseOperativeEffect effect) { - super(effect); - } - - @Override - public FlamewarStreetwiseOperativeEffect copy() { - return new FlamewarStreetwiseOperativeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - int damage = (Integer) getValue("damage"); - if (player == null || damage < 1) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, damage)); - player.moveCards(cards, Zone.EXILED, source, game); - cards.retainZone(Zone.EXILED, game); - cards.getCards(game).stream().forEach(card -> { - card.setFaceDown(true, game); - card.addCounters(CounterType.INTEL.createInstance(), source, game); - }); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FlashConscription.java b/Mage.Sets/src/mage/cards/f/FlashConscription.java index 189881c60b1..b4fba0da72f 100644 --- a/Mage.Sets/src/mage/cards/f/FlashConscription.java +++ b/Mage.Sets/src/mage/cards/f/FlashConscription.java @@ -1,10 +1,9 @@ - package mage.cards.f; -import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsCombatDamageTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -13,15 +12,11 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author LevelX2 @@ -36,7 +31,10 @@ public final class FlashConscription extends CardImpl { this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn).setText("and gain control of it until end of turn")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("That creature gains haste until end of turn")); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( - new GainAbilityTargetEffect(new FlashConscriptionTriggeredAbility(), Duration.EndOfTurn), + new GainAbilityTargetEffect( + new DealsCombatDamageTriggeredAbility(new GainLifeEffect(SavedDamageValue.MUCH), false), + Duration.EndOfTurn + ), ManaWasSpentCondition.WHITE, "If {W} was spent to cast this spell, the creature gains " + "\"Whenever this creature deals combat damage, you gain that much life\" until end of turn" @@ -54,43 +52,3 @@ public final class FlashConscription extends CardImpl { return new FlashConscription(this); } } - -class FlashConscriptionTriggeredAbility extends TriggeredAbilityImpl { - - public FlashConscriptionTriggeredAbility() { - super(Zone.BATTLEFIELD, null); - } - - private FlashConscriptionTriggeredAbility(final FlashConscriptionTriggeredAbility ability) { - super(ability); - } - - @Override - public FlashConscriptionTriggeredAbility copy() { - return new FlashConscriptionTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT - || event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedEvent damageEvent = (DamagedEvent) event; - if (damageEvent.isCombatDamage()) { - if (event.getSourceId().equals(this.sourceId)) { - this.getEffects().clear(); - this.getEffects().add(new GainLifeEffect(damageEvent.getAmount())); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage, you gain that much life."; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FlashPhotography.java b/Mage.Sets/src/mage/cards/f/FlashPhotography.java index 871cf8e8514..c3fbb6955bb 100644 --- a/Mage.Sets/src/mage/cards/f/FlashPhotography.java +++ b/Mage.Sets/src/mage/cards/f/FlashPhotography.java @@ -26,7 +26,7 @@ public final class FlashPhotography extends CardImpl { // You may cast this spell as though it had flash if it targets a permanent you control. this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( - condition, "you may cast this spell as though it had flash if it targets a permanent you control" + condition, "you may cast this spell as though it had flash if it targets a permanent you control." )); // Create a token that's a copy of target permanent. diff --git a/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java b/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java index c315c30d5e6..5ccc0816900 100644 --- a/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java +++ b/Mage.Sets/src/mage/cards/f/FlexibleWaterbender.java @@ -32,7 +32,7 @@ public final class FlexibleWaterbender extends CardImpl { // Waterbend {3}: This creature has base power and toughness 5/2 until end of turn. this.addAbility(new SimpleActivatedAbility( - new SetBasePowerToughnessSourceEffect(3, 2, Duration.EndOfTurn), new WaterbendCost(3) + new SetBasePowerToughnessSourceEffect(5, 2, Duration.EndOfTurn), new WaterbendCost(3) )); } diff --git a/Mage.Sets/src/mage/cards/f/FoggyBottomSwamp.java b/Mage.Sets/src/mage/cards/f/FoggyBottomSwamp.java new file mode 100644 index 00000000000..f073c26d9c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggyBottomSwamp.java @@ -0,0 +1,48 @@ +package mage.cards.f; + +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.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoggyBottomSwamp extends CardImpl { + + public FoggyBottomSwamp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {B} or {G}. + this.addAbility(new BlackManaAbility()); + this.addAbility(new GreenManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private FoggyBottomSwamp(final FoggyBottomSwamp card) { + super(card); + } + + @Override + public FoggyBottomSwamp copy() { + return new FoggyBottomSwamp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampHunters.java b/Mage.Sets/src/mage/cards/f/FoggySwampHunters.java new file mode 100644 index 00000000000..57290f092f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggySwampHunters.java @@ -0,0 +1,53 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DrewTwoOrMoreCardsCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.LifelinkAbility; +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 FoggySwampHunters extends CardImpl { + + public FoggySwampHunters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.RANGER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // As long as you've drawn two or more cards this turn, this creature has lifelink and menace. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(LifelinkAbility.getInstance()), DrewTwoOrMoreCardsCondition.instance, + "as long as you've drawn two or more cards this turn, {this} has lifelink" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new MenaceAbility(false)), + DrewTwoOrMoreCardsCondition.instance, "and menace" + )); + this.addAbility(ability.addHint(CardsDrawnThisTurnDynamicValue.getHint())); + } + + private FoggySwampHunters(final FoggySwampHunters card) { + super(card); + } + + @Override + public FoggySwampHunters copy() { + return new FoggySwampHunters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampSpiritKeeper.java b/Mage.Sets/src/mage/cards/f/FoggySwampSpiritKeeper.java new file mode 100644 index 00000000000..34f7ebcd407 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggySwampSpiritKeeper.java @@ -0,0 +1,44 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.SpiritWorldToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoggySwampSpiritKeeper extends CardImpl { + + public FoggySwampSpiritKeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever you draw your second card each turn, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + this.addAbility(new DrawNthCardTriggeredAbility(new CreateTokenEffect(new SpiritWorldToken()))); + } + + private FoggySwampSpiritKeeper(final FoggySwampSpiritKeeper card) { + super(card); + } + + @Override + public FoggySwampSpiritKeeper copy() { + return new FoggySwampSpiritKeeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampVinebender.java b/Mage.Sets/src/mage/cards/f/FoggySwampVinebender.java new file mode 100644 index 00000000000..a34af151b15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggySwampVinebender.java @@ -0,0 +1,49 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DauntAbility; +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 FoggySwampVinebender extends CardImpl { + + public FoggySwampVinebender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // This creature can't be blocked by creatures with power 2 or less. + this.addAbility(new DauntAbility()); + + // Waterbend {5}: Put a +1/+1 counter on this creature. Activate only during your turn. + this.addAbility(new ActivateIfConditionActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new WaterbendCost(5), MyTurnCondition.instance + )); + } + + private FoggySwampVinebender(final FoggySwampVinebender card) { + super(card); + } + + @Override + public FoggySwampVinebender copy() { + return new FoggySwampVinebender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java new file mode 100644 index 00000000000..f1ad9b03694 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoggySwampVisions.java @@ -0,0 +1,94 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.cards.*; +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.common.TargetCardInGraveyard; +import mage.target.targetadjustment.XManaValueTargetAdjuster; +import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoggySwampVisions extends CardImpl { + + public FoggySwampVisions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Exile X target creature cards from graveyards. For each creature card exiled this way, create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens. + this.getSpellAbility().addEffect(new FoggySwampVisionsEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURES)); + this.getSpellAbility().setTargetAdjuster(new XManaValueTargetAdjuster()); + } + + private FoggySwampVisions(final FoggySwampVisions card) { + super(card); + } + + @Override + public FoggySwampVisions copy() { + return new FoggySwampVisions(this); + } +} + +class FoggySwampVisionsEffect extends OneShotEffect { + + FoggySwampVisionsEffect() { + super(Outcome.Benefit); + staticText = "exile X target creature cards from graveyards. For each creature card exiled this way, " + + "create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens."; + } + + private FoggySwampVisionsEffect(final FoggySwampVisionsEffect effect) { + super(effect); + } + + @Override + public FoggySwampVisionsEffect copy() { + return new FoggySwampVisionsEffect(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.retainZone(Zone.EXILED, game); + Set permanents = new HashSet<>(); + for (Card card : cards.getCards(game)) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.setTargetPointer(new FixedTarget(card, game)); + effect.apply(game, source); + permanents.addAll(effect.getAddedPermanents()); + } + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice those tokens") + .setTargetPointer(new FixedTargets(permanents, game)), + TargetController.YOU + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForebodingStatue.java b/Mage.Sets/src/mage/cards/f/ForebodingStatue.java index c9b454f25a3..a850e83d438 100644 --- a/Mage.Sets/src/mage/cards/f/ForebodingStatue.java +++ b/Mage.Sets/src/mage/cards/f/ForebodingStatue.java @@ -1,49 +1,57 @@ package mage.cards.f; -import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.mana.AnyColorManaAbility; -import mage.constants.SubType; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import mage.counters.CounterType; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class ForebodingStatue extends CardImpl { +public final class ForebodingStatue extends TransformingDoubleFacedCard { public ForebodingStatue(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.CONSTRUCT}, "{3}", + "Forsaken Thresher", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.CONSTRUCT}, "" + ); - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.f.ForsakenThresher.class; + // Foreboding Statue + this.getLeftHalfCard().setPT(1, 2); // {T}: Add one mana of any color. Put an omen counter on Foreboding Statue. Ability ability = new AnyColorManaAbility(); ability.addEffect(new AddCountersSourceEffect(CounterType.OMEN.createInstance())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your end step, if there are three or more omen counters on Foreboding Statue, untap it, then transform it. - this.addAbility(new TransformAbility()); ability = new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new UntapSourceEffect().setText("untap it,"), false, new SourceHasCounterCondition(CounterType.OMEN, 3) ); ability.addEffect(new TransformSourceEffect().setText("then transform it")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Forsaken Thresher + this.getRightHalfCard().setPT(5, 5); + + // At the beginning of your precombat main phase, add one mana of any color. + this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(new AddManaOfAnyColorEffect())); } private ForebodingStatue(final ForebodingStatue card) { diff --git a/Mage.Sets/src/mage/cards/f/ForecastingFortuneTeller.java b/Mage.Sets/src/mage/cards/f/ForecastingFortuneTeller.java new file mode 100644 index 00000000000..d994797a041 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForecastingFortuneTeller.java @@ -0,0 +1,40 @@ +package mage.cards.f; + +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.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ForecastingFortuneTeller extends CardImpl { + + public ForecastingFortuneTeller(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When this creature enters, create a Clue token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + } + + private ForecastingFortuneTeller(final ForecastingFortuneTeller card) { + super(card); + } + + @Override + public ForecastingFortuneTeller copy() { + return new ForecastingFortuneTeller(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForgeDevil.java b/Mage.Sets/src/mage/cards/f/ForgeDevil.java index 6229e8bbba7..a5ce17b7fa7 100644 --- a/Mage.Sets/src/mage/cards/f/ForgeDevil.java +++ b/Mage.Sets/src/mage/cards/f/ForgeDevil.java @@ -1,22 +1,20 @@ - 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.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; 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 anonymous + * @author xenohedron */ public final class ForgeDevil extends CardImpl { @@ -28,13 +26,8 @@ public final class ForgeDevil extends CardImpl { this.toughness = new MageInt(1); // When Forge Devil enters the battlefield, it deals 1 damage to target creature and 1 damage to you. - Effect effect = new DamageTargetEffect(1); - effect.setText("it deals 1 damage to target creature"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetAndYouEffect(1)); ability.addTarget(new TargetCreaturePermanent()); - effect = new DamageControllerEffect(1); - effect.setText("and 1 damage to you"); - ability.addEffect(effect); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FoundingOfOmashu.java b/Mage.Sets/src/mage/cards/f/FoundingOfOmashu.java new file mode 100644 index 00000000000..3e642cc27e8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoundingOfOmashu.java @@ -0,0 +1,51 @@ +package mage.cards.f; + +import mage.abilities.common.SagaAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.SagaChapter; +import mage.constants.SubType; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoundingOfOmashu extends CardImpl { + + public FoundingOfOmashu(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Create two 1/1 white Ally creature tokens. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new AllyToken(), 2)); + + // II -- You may discard a card. If you do, draw a card. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost())); + + // III -- Creatures you control get +1/+0 until end of turn. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new BoostControlledEffect(1, 0, Duration.EndOfTurn)); + this.addAbility(sagaAbility); + } + + private FoundingOfOmashu(final FoundingOfOmashu card) { + super(card); + } + + @Override + public FoundingOfOmashu copy() { + return new FoundingOfOmashu(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FragmentOfKonda.java b/Mage.Sets/src/mage/cards/f/FragmentOfKonda.java deleted file mode 100644 index 77b85acde32..00000000000 --- a/Mage.Sets/src/mage/cards/f/FragmentOfKonda.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.DefenderAbility; -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 FragmentOfKonda extends CardImpl { - - public FragmentOfKonda(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.nightCard = true; - - // Defender - this.addAbility(DefenderAbility.getInstance()); - - // When Fragment of Konda dies, draw a card. - this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1))); - } - - private FragmentOfKonda(final FragmentOfKonda card) { - super(card); - } - - @Override - public FragmentOfKonda copy() { - return new FragmentOfKonda(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FranticConfrontation.java b/Mage.Sets/src/mage/cards/f/FranticConfrontation.java new file mode 100644 index 00000000000..b9c4d989924 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FranticConfrontation.java @@ -0,0 +1,42 @@ +package mage.cards.f; + +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FranticConfrontation extends CardImpl { + + public FranticConfrontation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); + + // Target creature you control gets +X/+0 and gains first strike and trample until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(GetXValue.instance, StaticValue.get(0)) + .setText("target creature you control gets +X/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()) + .setText("and gains first strike")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()) + .setText("and trample until end of turn")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private FranticConfrontation(final FranticConfrontation card) { + super(card); + } + + @Override + public FranticConfrontation copy() { + return new FranticConfrontation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FreedomFighterRecruit.java b/Mage.Sets/src/mage/cards/f/FreedomFighterRecruit.java new file mode 100644 index 00000000000..9ea0d9c8c2c --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FreedomFighterRecruit.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; +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 FreedomFighterRecruit extends CardImpl { + + public FreedomFighterRecruit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Freedom Fighter Recruit's power is equal to the number of creatures you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerSourceEffect(CreaturesYouControlCount.PLURAL))); + } + + private FreedomFighterRecruit(final FreedomFighterRecruit card) { + super(card); + } + + @Override + public FreedomFighterRecruit copy() { + return new FreedomFighterRecruit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FrenziedTrapbreaker.java b/Mage.Sets/src/mage/cards/f/FrenziedTrapbreaker.java deleted file mode 100644 index 8da3b71319d..00000000000 --- a/Mage.Sets/src/mage/cards/f/FrenziedTrapbreaker.java +++ /dev/null @@ -1,67 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.keyword.NightboundAbility; -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.FilterArtifactOrEnchantmentPermanent; -import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class FrenziedTrapbreaker extends CardImpl { - - private static final FilterPermanent filter - = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment defending player controls"); - - static { - filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); - } - - public FrenziedTrapbreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // {1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment. - Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(1)); - ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); - this.addAbility(ability); - - // Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls. - ability = new AttacksTriggeredAbility(new DestroyTargetEffect()); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private FrenziedTrapbreaker(final FrenziedTrapbreaker card) { - super(card); - } - - @Override - public FrenziedTrapbreaker copy() { - return new FrenziedTrapbreaker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/f/FullThrottle.java b/Mage.Sets/src/mage/cards/f/FullThrottle.java index 740867674f2..6783e96aca9 100644 --- a/Mage.Sets/src/mage/cards/f/FullThrottle.java +++ b/Mage.Sets/src/mage/cards/f/FullThrottle.java @@ -1,22 +1,25 @@ package mage.cards.f; -import java.util.UUID; - +import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.condition.common.IsMainPhaseCondition; +import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.*; +import mage.abilities.effects.common.AdditionalCombatPhaseEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.UntapAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackedThisTurnPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.turn.Turn; + +import java.util.UUID; /** - * * @author Jmlundeen */ public final class FullThrottle extends CardImpl { @@ -24,16 +27,15 @@ public final class FullThrottle extends CardImpl { public FullThrottle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); - // After this main phase, there are two additional combat phases. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new AdditionalCombatPhaseEffect(2), - IsMainPhaseCondition.ANY, + new AdditionalCombatPhaseEffect(2), FullThrottleCondition.instance, "After this main phase, there are two additional combat phases." )); + // At the beginning of each combat this turn, untap all creatures that attacked this turn. - DelayedTriggeredAbility ability = new FullThrottleTriggeredAbility(); - this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(ability).concatBy("
")); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new FullThrottleTriggeredAbility()) + .concatBy("
")); } private FullThrottle(final FullThrottle card) { @@ -46,14 +48,25 @@ public final class FullThrottle extends CardImpl { } } +enum FullThrottleCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.getTurnPhaseType().isMain(); + } +} + class FullThrottleTriggeredAbility extends DelayedTriggeredAbility { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that attacked this turn"); + + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures that attacked this turn"); static { filter.add(AttackedThisTurnPredicate.instance); } + public FullThrottleTriggeredAbility() { - super(new UntapAllEffect(filter), Duration.EndOfTurn, false); + super(new UntapAllEffect(filter), Duration.EndOfTurn, false, false); setTriggerPhrase("At the beginning of each combat this turn, "); } @@ -73,7 +86,6 @@ class FullThrottleTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - Turn turn = game.getState().getTurn(); - return turn.getPhase().getType() == TurnPhase.COMBAT; + return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/f/Fumble.java b/Mage.Sets/src/mage/cards/f/Fumble.java index b0ddcaa6973..8fbdb8b027e 100644 --- a/Mage.Sets/src/mage/cards/f/Fumble.java +++ b/Mage.Sets/src/mage/cards/f/Fumble.java @@ -97,7 +97,7 @@ class FumbleEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(attachment, game)); game.addEffect(effect, source); if (newCreature != null) { - attachment.attachTo(newCreature.getId(), source, game); + newCreature.addAttachment(attachment.getId(), source, game); } } } diff --git a/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java b/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java new file mode 100644 index 00000000000..23d75f79f87 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FuneralRoomAwakeningHall.java @@ -0,0 +1,48 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.ReturnFromYourGraveyardToBattlefieldAllEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class FuneralRoomAwakeningHall extends RoomCard { + + public FuneralRoomAwakeningHall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{B}", "{6}{B}{B}"); + this.subtype.add(SubType.ROOM); + + // Funeral Room: Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life. + Ability left = new DiesCreatureTriggeredAbility( + new LoseLifeOpponentsEffect(1), false, + StaticFilters.FILTER_CONTROLLED_A_CREATURE + ); + left.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getLeftHalfCard().addAbility(left); + + // Awakening Hall: When you unlock this door, return all creature cards from your graveyard to the battlefield. + Ability right = new UnlockThisDoorTriggeredAbility( + new ReturnFromYourGraveyardToBattlefieldAllEffect(StaticFilters.FILTER_CARD_CREATURES), false, false + ); + this.getRightHalfCard().addAbility(right); + } + + private FuneralRoomAwakeningHall(final FuneralRoomAwakeningHall card) { + super(card); + } + + @Override + public FuneralRoomAwakeningHall copy() { + return new FuneralRoomAwakeningHall(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FuriousReprisal.java b/Mage.Sets/src/mage/cards/f/FuriousReprisal.java index 4f99b3d599f..1ead08841c9 100644 --- a/Mage.Sets/src/mage/cards/f/FuriousReprisal.java +++ b/Mage.Sets/src/mage/cards/f/FuriousReprisal.java @@ -18,7 +18,7 @@ public final class FuriousReprisal extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Furious Reprisal deals 2 damage to each of two target creatures and/or players. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "each of two targets")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("each of two targets")); this.getSpellAbility().addTarget(new TargetAnyTarget(2, 2)); } diff --git a/Mage.Sets/src/mage/cards/f/FurnaceBlessedConqueror.java b/Mage.Sets/src/mage/cards/f/FurnaceBlessedConqueror.java deleted file mode 100644 index 3b69d44dcf8..00000000000 --- a/Mage.Sets/src/mage/cards/f/FurnaceBlessedConqueror.java +++ /dev/null @@ -1,88 +0,0 @@ -package mage.cards.f; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -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.counters.CounterType; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class FurnaceBlessedConqueror extends CardImpl { - - public FurnaceBlessedConqueror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setRed(true); - this.nightCard = true; - - // Whenever Furnace-Blessed Conqueror attacks, create a tapped and attacking token that's a copy of it. Put a +1/+1 counter on that token for each +1/+1 counter on Furnace-Blessed Conqueror. Sacrifice that token at the beginning of the next end step. - this.addAbility(new AttacksTriggeredAbility(new FurnaceBlessedConquerorEffect())); - } - - private FurnaceBlessedConqueror(final FurnaceBlessedConqueror card) { - super(card); - } - - @Override - public FurnaceBlessedConqueror copy() { - return new FurnaceBlessedConqueror(this); - } -} - -class FurnaceBlessedConquerorEffect extends OneShotEffect { - - FurnaceBlessedConquerorEffect() { - super(Outcome.Benefit); - staticText = "create a tapped and attacking token that's a copy of it. " + - "Put a +1/+1 counter on that token for each +1/+1 counter on {this}. " + - "Sacrifice that token at the beginning of the next end step"; - } - - private FurnaceBlessedConquerorEffect(final FurnaceBlessedConquerorEffect effect) { - super(effect); - } - - @Override - public FurnaceBlessedConquerorEffect copy() { - return new FurnaceBlessedConquerorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( - null, null, false, 1, true, true - ); - effect.setSavedPermanent(permanent); - effect.apply(game, source); - effect.sacrificeTokensCreatedAtNextEndStep(game, source); - int counters = permanent.getCounters(game).getCount(CounterType.P1P1); - if (counters < 1) { - return true; - } - for (Permanent token : effect.getAddedPermanents()) { - token.addCounters(CounterType.P1P1.createInstance(counters), source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FurnaceCelebration.java b/Mage.Sets/src/mage/cards/f/FurnaceCelebration.java index 484a37433a5..5ffc9e8dfca 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceCelebration.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceCelebration.java @@ -8,30 +8,23 @@ import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.target.common.TargetAnyTarget; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class FurnaceCelebration extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public FurnaceCelebration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); // Whenever you sacrifice another permanent, you may pay {2}. If you do, Furnace Celebration deals 2 damage to any target. Ability ability = new SacrificePermanentTriggeredAbility(new DoIfCostPaid( - new DamageTargetEffect(2), new GenericManaCost(2)), filter); + new DamageTargetEffect(2), new GenericManaCost(2) + ), StaticFilters.FILTER_ANOTHER_PERMANENT); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java index 3eabea17458..fd55df86f03 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java @@ -28,7 +28,7 @@ public final class FurnaceScamp extends CardImpl { // Whenever Furnace Scamp deals combat damage to a player, you may sacrifice it. If you do, Furnace Scamp deals 3 damage to that player. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( - new DamageTargetEffect(3, true, "that player"), new SacrificeSourceCost() + new DamageTargetEffect(3).withTargetDescription("that player"), new SacrificeSourceCost() ), false, true); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Galedrifter.java b/Mage.Sets/src/mage/cards/g/Galedrifter.java index c76b1198447..e8ac03ad82b 100644 --- a/Mage.Sets/src/mage/cards/g/Galedrifter.java +++ b/Mage.Sets/src/mage/cards/g/Galedrifter.java @@ -1,11 +1,9 @@ package mage.cards.g; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,21 +12,29 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class Galedrifter extends CardImpl { +public final class Galedrifter extends TransformingDoubleFacedCard { public Galedrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF}, "{3}{U}", + "Waildrifter", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF, SubType.SPIRIT}, "U"); - this.subtype.add(SubType.HIPPOGRIFF); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.w.Waildrifter.class; + this.getLeftHalfCard().setPT(3, 2); + this.getRightHalfCard().setPT(2, 2); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Disturb {4}{U} - this.addAbility(new DisturbAbility(this, "{4}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{U}")); + + // Waildrifter + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // If Waildrifter would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private Galedrifter(final Galedrifter card) { diff --git a/Mage.Sets/src/mage/cards/g/GalianBeast.java b/Mage.Sets/src/mage/cards/g/GalianBeast.java deleted file mode 100644 index 9ff6b2f8107..00000000000 --- a/Mage.Sets/src/mage/cards/g/GalianBeast.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; -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 mage.constants.SuperType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GalianBeast extends CardImpl { - - public GalianBeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.nightCard = true; - this.color.setBlack(true); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // When Galian Beast dies, return it to the battlefield tapped. - this.addAbility(new DiesSourceTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true) - .setText("return it to the battlefield tapped"))); - } - - private GalianBeast(final GalianBeast card) { - super(card); - } - - @Override - public GalianBeast copy() { - return new GalianBeast(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GargantuanSlabhorn.java b/Mage.Sets/src/mage/cards/g/GargantuanSlabhorn.java deleted file mode 100644 index dd19a481a83..00000000000 --- a/Mage.Sets/src/mage/cards/g/GargantuanSlabhorn.java +++ /dev/null @@ -1,66 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.TrampleAbility; -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.filter.FilterPermanent; -import mage.filter.predicate.permanent.TransformedPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GargantuanSlabhorn extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("transformed permanents"); - - static { - filter.add(TransformedPredicate.instance); - } - - public GargantuanSlabhorn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.BEAST); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); - - // Other transformed permanents you control have trample and ward {2}. - Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true - )); - ability.addEffect(new GainAbilityControlledEffect( - new WardAbility(new GenericManaCost(2)), Duration.WhileOnBattlefield, filter, true - ).setText("and ward {2}")); - this.addAbility(ability); - } - - private GargantuanSlabhorn(final GargantuanSlabhorn card) { - super(card); - } - - @Override - public GargantuanSlabhorn copy() { - return new GargantuanSlabhorn(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GarlandKnightOfCornelia.java b/Mage.Sets/src/mage/cards/g/GarlandKnightOfCornelia.java index 80580939181..b6d5a06f9a1 100644 --- a/Mage.Sets/src/mage/cards/g/GarlandKnightOfCornelia.java +++ b/Mage.Sets/src/mage/cards/g/GarlandKnightOfCornelia.java @@ -1,16 +1,18 @@ package mage.cards.g; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnLibrarySourceEffect; import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; @@ -22,29 +24,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class GarlandKnightOfCornelia extends CardImpl { +public final class GarlandKnightOfCornelia extends TransformingDoubleFacedCard { public GarlandKnightOfCornelia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "{B}{R}", + "Chaos, the Endless", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "BR" + ); - this.secondSideCardClazz = mage.cards.c.ChaosTheEndless.class; - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(2); + // Garland, Knight of Cornelia + this.getLeftHalfCard().setPT(3, 2); // Whenever you cast a noncreature spell, surveil 1. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( new SurveilEffect(1), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false )); // {3}{B}{B}{R}{R}: Return this card from your graveyard to the battlefield transformed. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( Zone.GRAVEYARD, new GarlandKnightOfCorneliaEffect(), new ManaCostsImpl<>("{3}{B}{B}{R}{R}") )); + + // Chaos, the Endless + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When Chaos dies, put it on the bottom of its owner's library. + this.getRightHalfCard().addAbility(new DiesSourceTriggeredAbility(new PutOnLibrarySourceEffect( + false, "put it on the bottom of its owner's library" + ), false)); } private GarlandKnightOfCornelia(final GarlandKnightOfCornelia card) { diff --git a/Mage.Sets/src/mage/cards/g/GarlandRoyalKidnapper.java b/Mage.Sets/src/mage/cards/g/GarlandRoyalKidnapper.java new file mode 100644 index 00000000000..28d09f9e005 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarlandRoyalKidnapper.java @@ -0,0 +1,173 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.BecomesMonarchTargetEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.hint.common.MonarchHint; +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.ControllerIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GarlandRoyalKidnapper extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("creatures you control but don't own"); + + static { + filter.add(TargetController.NOT_YOU.getOwnerPredicate()); + } + + public GarlandRoyalKidnapper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Garland enters, target opponent becomes the monarch. + Ability ability = new EntersBattlefieldTriggeredAbility(new BecomesMonarchTargetEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability.addHint(MonarchHint.instance)); + + // Whenever an opponent becomes the monarch, gain control of target creature that player controls for as long as they're the monarch. + this.addAbility(new GarlandRoyalKidnapperTriggeredAbility()); + + // Creatures you control but don't own get +2/+2 and can't be sacrificed. + ability = new SimpleStaticAbility(new BoostAllEffect( + 2, 2, Duration.WhileOnBattlefield, filter, false + )); + ability.addEffect(new GarlandRoyalKidnapperSacrificeEffect()); + this.addAbility(ability); + } + + private GarlandRoyalKidnapper(final GarlandRoyalKidnapper card) { + super(card); + } + + @Override + public GarlandRoyalKidnapper copy() { + return new GarlandRoyalKidnapper(this); + } +} + +class GarlandRoyalKidnapperTriggeredAbility extends TriggeredAbilityImpl { + + GarlandRoyalKidnapperTriggeredAbility() { + super(Zone.BATTLEFIELD, new GarlandRoyalKidnapperControlEffect()); + this.addTarget(new TargetOpponent()); + this.setTriggerPhrase("Whenever an opponent becomes the monarch, "); + } + + private GarlandRoyalKidnapperTriggeredAbility(final GarlandRoyalKidnapperTriggeredAbility ability) { + super(ability); + } + + @Override + public GarlandRoyalKidnapperTriggeredAbility copy() { + return new GarlandRoyalKidnapperTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BECOMES_MONARCH; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(event.getTargetId()); + if (player == null || !game.getOpponents(getControllerId()).contains(player.getId())) { + return false; + } + FilterPermanent filter = new FilterCreaturePermanent("creature controlled by " + player.getName()); + filter.add(new ControllerIdPredicate(player.getId())); + this.getTargets().clear(); + this.addTarget(new TargetPermanent(filter)); + this.getEffects().setValue("monarchId", player.getId()); + return true; + } +} + +class GarlandRoyalKidnapperControlEffect extends GainControlTargetEffect { + + GarlandRoyalKidnapperControlEffect() { + super(Duration.Custom, true); + staticText = "gain control of target creature that player controls for as long as they're the monarch"; + } + + private GarlandRoyalKidnapperControlEffect(final GarlandRoyalKidnapperControlEffect effect) { + super(effect); + } + + @Override + public GarlandRoyalKidnapperControlEffect copy() { + return new GarlandRoyalKidnapperControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null + && Optional + .ofNullable((UUID) getValue("monarchId")) + .filter(uuid -> uuid.equals(game.getMonarchId())) + .isPresent()) { + return super.apply(game, source); + } + discard(); + return false; + } +} + +class GarlandRoyalKidnapperSacrificeEffect extends ContinuousEffectImpl { + + GarlandRoyalKidnapperSacrificeEffect() { + super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit); + staticText = "and can't be sacrificed"; + } + + private GarlandRoyalKidnapperSacrificeEffect(final GarlandRoyalKidnapperSacrificeEffect effect) { + super(effect); + } + + @Override + public GarlandRoyalKidnapperSacrificeEffect copy() { + return new GarlandRoyalKidnapperSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game + )) { + if (!permanent.isOwnedBy(source.getControllerId())) { + permanent.setCanBeSacrificed(true); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarrukRelentless.java b/Mage.Sets/src/mage/cards/g/GarrukRelentless.java index b22ae5c3b93..c39b05e92e6 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukRelentless.java +++ b/Mage.Sets/src/mage/cards/g/GarrukRelentless.java @@ -3,19 +3,29 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.StateTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; +import mage.game.permanent.token.WolfTokenWithDeathtouch; +import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -23,29 +33,54 @@ import java.util.UUID; /** * @author nantuko */ -public final class GarrukRelentless extends CardImpl { +public final class GarrukRelentless extends TransformingDoubleFacedCard { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE); public GarrukRelentless(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{G}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GARRUK); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.GARRUK}, "{3}{G}", + "Garruk, the Veil-Cursed", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.GARRUK}, "BG" + ); - this.secondSideCardClazz = mage.cards.g.GarrukTheVeilCursed.class; - - this.setStartingLoyalty(3); + // Garruk Relentless + this.getLeftHalfCard().setStartingLoyalty(3); // When Garruk Relentless has two or fewer loyalty counters on him, transform him. - this.addAbility(new TransformAbility()); - this.addAbility(new GarrukRelentlessStateTrigger()); + this.getLeftHalfCard().addAbility(new GarrukRelentlessStateTrigger()); - // 0: Garruk Relentless deals 3 damage to target creature. That creature deals damage equal to its power to him + // 0: Garruk Relentless deals 3 damage to target creature. That creature deals damage equal to its power to him. Ability ability = new LoyaltyAbility(new DamageTargetEffect(3), 0); ability.addEffect(new GarrukRelentlessDamageEffect()); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // 0: Create a 2/2 green Wolf creature token. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0)); + this.getLeftHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0)); + + // Garruk, the Veil-Cursed + // +1: Create a 1/1 black Wolf creature token with deathtouch. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfTokenWithDeathtouch()), 1)); + + // -1: Sacrifice a creature. If you do, search your library for a creature card, reveal it, put it into your hand, then shuffle. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new DoIfCostPaid( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary( + StaticFilters.FILTER_CARD_CREATURE_A + ), true), + null, + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), + false + ), -1)); + + // -3: Creatures you control gain trample and get +X/+X until end of turn, where X is the number of creature cards in your graveyard. + Ability backAbility = new LoyaltyAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("creatures you control gain trample"), -3); + backAbility.addEffect(new BoostControlledEffect( + xValue, xValue, Duration.EndOfTurn + ).setText("and get +X/+X until end of turn, where X is the number of creature cards in your graveyard")); + this.getRightHalfCard().addAbility(backAbility); } private GarrukRelentless(final GarrukRelentless card) { @@ -60,7 +95,7 @@ public final class GarrukRelentless extends CardImpl { class GarrukRelentlessStateTrigger extends StateTriggeredAbility { - public GarrukRelentlessStateTrigger() { + GarrukRelentlessStateTrigger() { super(Zone.BATTLEFIELD, new TransformSourceEffect()); } @@ -109,5 +144,4 @@ class GarrukRelentlessDamageEffect extends OneShotEffect { public GarrukRelentlessDamageEffect copy() { return new GarrukRelentlessDamageEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java b/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java deleted file mode 100644 index 4bd063d6f6f..00000000000 --- a/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java +++ /dev/null @@ -1,75 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -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.filter.StaticFilters; -import mage.game.permanent.token.WolfTokenWithDeathtouch; -import mage.target.common.TargetCardInLibrary; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class GarrukTheVeilCursed extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE); - - public GarrukTheVeilCursed(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GARRUK); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.color.setGreen(true); - this.color.setBlack(true); - - // +1 : Create a 1/1 black Wolf creature token with deathtouch. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfTokenWithDeathtouch()), 1)); - - // -1 : Sacrifice a creature. If you do, search your library for a creature card, reveal it, put it into your hand, then shuffle your library. - this.addAbility(new LoyaltyAbility(new DoIfCostPaid( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary( - StaticFilters.FILTER_CARD_CREATURE_A - ), true), - null, - new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE), - false - ), -1)); - - // -3 : Creatures you control gain trample and get +X/+X until end of turn, where X is the number of creature cards in your graveyard. - Ability ability = new LoyaltyAbility(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("creatures you control gain trample"), -3); - ability.addEffect(new BoostControlledEffect( - xValue, xValue, Duration.EndOfTurn - ).setText("and get +X/+X until end of turn, where X is the number of creature cards in your graveyard")); - this.addAbility(ability); - } - - private GarrukTheVeilCursed(final GarrukTheVeilCursed card) { - super(card); - } - - @Override - public GarrukTheVeilCursed copy() { - return new GarrukTheVeilCursed(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GatherTheWhiteLotus.java b/Mage.Sets/src/mage/cards/g/GatherTheWhiteLotus.java new file mode 100644 index 00000000000..f280c96fcb6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatherTheWhiteLotus.java @@ -0,0 +1,43 @@ +package mage.cards.g; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.ScryEffect; +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.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatherTheWhiteLotus extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.PLAINS)); + private static final Hint hint = new ValueHint("Plains you control", xValue); + + public GatherTheWhiteLotus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + // Create a 1/1 white Ally creature token for each Plains you control. Scry 2. + this.getSpellAbility().addEffect(new CreateTokenEffect(new AllyToken(), xValue)); + this.getSpellAbility().addEffect(new ScryEffect(2)); + this.getSpellAbility().addHint(hint); + } + + private GatherTheWhiteLotus(final GatherTheWhiteLotus card) { + super(card); + } + + @Override + public GatherTheWhiteLotus copy() { + return new GatherTheWhiteLotus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatstafArsonists.java b/Mage.Sets/src/mage/cards/g/GatstafArsonists.java index 95ee3a5336b..52b343bda84 100644 --- a/Mage.Sets/src/mage/cards/g/GatstafArsonists.java +++ b/Mage.Sets/src/mage/cards/g/GatstafArsonists.java @@ -1,32 +1,42 @@ package mage.cards.g; -import java.util.UUID; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; /** - * * @author LevelX2 */ -public final class GatstafArsonists extends CardImpl { +public final class GatstafArsonists extends TransformingDoubleFacedCard { public GatstafArsonists(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{R}", + "Gatstaf Ravagers", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.g.GatstafRavagers.class; + // Gatstaf Arsonists + this.getLeftHalfCard().setPT(5, 4); // At the beginning of each upkeep, if no spells were cast last turn, transform Gatstaf Arsonists. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Gatstaf Ravagers + this.getRightHalfCard().setPT(6, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Gatstaf Ravagers. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private GatstafArsonists(final GatstafArsonists card) { diff --git a/Mage.Sets/src/mage/cards/g/GatstafHowler.java b/Mage.Sets/src/mage/cards/g/GatstafHowler.java deleted file mode 100644 index 3d98791e211..00000000000 --- a/Mage.Sets/src/mage/cards/g/GatstafHowler.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.keyword.IntimidateAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class GatstafHowler extends CardImpl { - - public GatstafHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.addAbility(IntimidateAbility.getInstance()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Gatstaf Howler. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private GatstafHowler(final GatstafHowler card) { - super(card); - } - - @Override - public GatstafHowler copy() { - return new GatstafHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GatstafRavagers.java b/Mage.Sets/src/mage/cards/g/GatstafRavagers.java deleted file mode 100644 index fd2463f180d..00000000000 --- a/Mage.Sets/src/mage/cards/g/GatstafRavagers.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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 LevelX2 - */ -public final class GatstafRavagers extends CardImpl { - - public GatstafRavagers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - - this.color.setRed(true); - - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Gatstaf Ravagers. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private GatstafRavagers(final GatstafRavagers card) { - super(card); - } - - @Override - public GatstafRavagers copy() { - return new GatstafRavagers(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GatstafShepherd.java b/Mage.Sets/src/mage/cards/g/GatstafShepherd.java index c23426f4896..8e011cbfc28 100644 --- a/Mage.Sets/src/mage/cards/g/GatstafShepherd.java +++ b/Mage.Sets/src/mage/cards/g/GatstafShepherd.java @@ -1,10 +1,10 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,21 +13,29 @@ import java.util.UUID; /** * @author nantuko */ -public final class GatstafShepherd extends CardImpl { +public final class GatstafShepherd extends TransformingDoubleFacedCard { public GatstafShepherd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}", + "Gatstaf Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.g.GatstafHowler.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(2); + // Gatstaf Shepherd + this.getLeftHalfCard().setPT(2, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Gatstaf Shepherd. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Gatstaf Howler + this.getRightHalfCard().setPT(3, 3); + + // Intimidate + this.getRightHalfCard().addAbility(IntimidateAbility.getInstance()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Gatstaf Howler. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private GatstafShepherd(final GatstafShepherd card) { diff --git a/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java index bbe616ea942..00e03c24ce8 100644 --- a/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java +++ b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.OrCost; @@ -14,9 +13,13 @@ 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.abilities.triggers.BeginningOfCombatTriggeredAbility; 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.counters.Counter; import mage.counters.CounterType; import mage.game.Game; @@ -57,7 +60,7 @@ public final class GavelOfTheRighteous extends CardImpl { Outcome.BoostCreature, new OrCost( "Pay {3} or remove a counter from {this}", - new GenericManaCost(3), new RemoveCountersSourceCost() + new GenericManaCost(3), new RemoveCountersSourceCost(1) ), false )); diff --git a/Mage.Sets/src/mage/cards/g/GeierReachBandit.java b/Mage.Sets/src/mage/cards/g/GeierReachBandit.java index 004e24bd542..2b2981a3248 100644 --- a/Mage.Sets/src/mage/cards/g/GeierReachBandit.java +++ b/Mage.Sets/src/mage/cards/g/GeierReachBandit.java @@ -1,37 +1,56 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; import java.util.UUID; /** * @author LevelX2 */ -public final class GeierReachBandit extends CardImpl { +public final class GeierReachBandit extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.WEREWOLF, "a Werewolf"); public GeierReachBandit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{2}{R}", + "Vildin-Pack Alpha", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.v.VildinPackAlpha.class; + // Geier Reach Bandit + this.getLeftHalfCard().setPT(3, 2); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // At the beginning of each upkeep, if no spells were cast last turn, transform Geier Reach Bandit. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Vildin-Pack Alpha + this.getRightHalfCard().setPT(4, 3); + + // Whenever a Werewolf you control enters, you may transform it. + this.getRightHalfCard().addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new VildinPackAlphaEffect(), filter, + true, SetTargetPointer.PERMANENT + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Vildin-Pack Alpha. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private GeierReachBandit(final GeierReachBandit card) { @@ -42,4 +61,34 @@ public final class GeierReachBandit extends CardImpl { public GeierReachBandit copy() { return new GeierReachBandit(this); } -} \ No newline at end of file +} + +class VildinPackAlphaEffect extends OneShotEffect { + + VildinPackAlphaEffect() { + super(Outcome.Benefit); + this.staticText = "you may transform it"; + } + + private VildinPackAlphaEffect(final VildinPackAlphaEffect effect) { + super(effect); + } + + @Override + public VildinPackAlphaEffect copy() { + return new VildinPackAlphaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Permanent werewolf = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (werewolf != null) { + werewolf.transform(source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GenerousSoul.java b/Mage.Sets/src/mage/cards/g/GenerousSoul.java deleted file mode 100644 index d0d85e6ad79..00000000000 --- a/Mage.Sets/src/mage/cards/g/GenerousSoul.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -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.SubType; - -import java.util.UUID; - -public final class GenerousSoul extends CardImpl { - - public GenerousSoul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - - // This is the back half of Beloved Beggar - this.nightCard = true; - - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(VigilanceAbility.getInstance()); - - // If Generous Soul would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GenerousSoul(final GenerousSoul card) { - super(card); - } - - @Override - public GenerousSoul copy() { - return new GenerousSoul(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java b/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java index daef4301cea..6807307ac58 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java +++ b/Mage.Sets/src/mage/cards/g/GenesisOfTheDaleks.java @@ -2,8 +2,7 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; @@ -19,7 +18,6 @@ import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.DalekToken; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -44,7 +42,7 @@ public final class GenesisOfTheDaleks extends CardImpl { // I, II, III -- Create a 3/3 black Dalek artifact creature token with menace for each lore counter on Genesis of the Daleks. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, - new CreateTokenEffect(new DalekToken(), GenesisOfTheDaleksValue.instance) + new CreateTokenEffect(new DalekToken(), new CountersSourceCount(CounterType.LORE)) ); // IV -- Target opponent faces a villainous choice -- Destroy all Dalek creatures and each of your opponents loses life equal to the total power of Daleks that died this turn, or destroy all non-Dalek creatures. @@ -65,41 +63,6 @@ public final class GenesisOfTheDaleks extends CardImpl { } } -enum GenesisOfTheDaleksValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Permanent permanent = sourceAbility.getSourcePermanentOrLKI(game); - if (permanent != null) { - return permanent - .getCounters(game) - .getCount(CounterType.LORE); - } - return Optional - .ofNullable(sourceAbility) - .map(Ability::getSourceId) - .map(game::getPermanentOrLKIBattlefield) - .map(p -> p.getCounters(game).getCount(CounterType.LORE)) - .orElse(0); - } - - @Override - public GenesisOfTheDaleksValue copy() { - return this; - } - - @Override - public String getMessage() { - return "lore counter on {this}"; - } - - @Override - public String toString() { - return "1"; - } -} - class GenesisOfTheDaleksEffect extends OneShotEffect { private static final FaceVillainousChoice choice = new FaceVillainousChoice( diff --git a/Mage.Sets/src/mage/cards/g/GeodeGrotto.java b/Mage.Sets/src/mage/cards/g/GeodeGrotto.java deleted file mode 100644 index 9bcf1d2c4c3..00000000000 --- a/Mage.Sets/src/mage/cards/g/GeodeGrotto.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.hint.common.ArtifactYouControlHint; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.mana.RedManaAbility; -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 GeodeGrotto extends CardImpl { - - public GeodeGrotto(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.subtype.add(SubType.CAVE); - this.nightCard = true; - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // {2}{R}, {T}: Until end of turn, target creature gains haste and gets +X/+0, where X is the number of artifacts you control. Activate only as a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility(new GainAbilityTargetEffect(HasteAbility.getInstance()) - .setText("Until end of turn, target creature gains haste"), new ManaCostsImpl<>("{2}{R}")); - ability.addCost(new TapSourceCost()); - ability.addEffect(new BoostTargetEffect( - ArtifactYouControlCount.instance, StaticValue.get(0) - ).setText("and gets +X/+0, where X is the number of artifacts you control")); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability.addHint(ArtifactYouControlHint.instance)); - } - - private GeodeGrotto(final GeodeGrotto card) { - super(card); - } - - @Override - public GeodeGrotto copy() { - return new GeodeGrotto(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhastlyHaunting.java b/Mage.Sets/src/mage/cards/g/GhastlyHaunting.java deleted file mode 100644 index 75e1bcf6701..00000000000 --- a/Mage.Sets/src/mage/cards/g/GhastlyHaunting.java +++ /dev/null @@ -1,47 +0,0 @@ - -package mage.cards.g; - -import java.util.UUID; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.ControlEnchantedEffect; -import mage.abilities.keyword.EnchantAbility; -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 mage.target.common.TargetCreaturePermanent; - -/** - * - * @author BetaSteward - */ -public final class GhastlyHaunting extends CardImpl { - - public GhastlyHaunting(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},""); - this.subtype.add(SubType.AURA); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.addAbility(new EnchantAbility(auraTarget)); - - // You control enchanted creature. - this.addAbility(new SimpleStaticAbility(new ControlEnchantedEffect())); - } - - private GhastlyHaunting(final GhastlyHaunting card) { - super(card); - } - - @Override - public GhastlyHaunting copy() { - return new GhastlyHaunting(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhastlyMimicry.java b/Mage.Sets/src/mage/cards/g/GhastlyMimicry.java deleted file mode 100644 index 85dce72078a..00000000000 --- a/Mage.Sets/src/mage/cards/g/GhastlyMimicry.java +++ /dev/null @@ -1,89 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GhastlyMimicry extends CardImpl { - - public GhastlyMimicry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // At the beginning of your upkeep, create a token that's a copy of enchanted creature, except it's a Spirit in addition to its other types. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GhastlyMimicryEffect())); - - // If Ghastly Mimicry would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GhastlyMimicry(final GhastlyMimicry card) { - super(card); - } - - @Override - public GhastlyMimicry copy() { - return new GhastlyMimicry(this); - } -} - -class GhastlyMimicryEffect extends OneShotEffect { - - GhastlyMimicryEffect() { - super(Outcome.Benefit); - staticText = "create a token that's a copy of enchanted creature, " + - "except it's a Spirit in addition to its other types"; - } - - private GhastlyMimicryEffect(final GhastlyMimicryEffect effect) { - super(effect); - } - - @Override - public GhastlyMimicryEffect copy() { - return new GhastlyMimicryEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentOrLKI(game); - if (permanent == null) { - return false; - } - Permanent attached = game.getPermanent(permanent.getAttachedTo()); - if (attached == null) { - return false; - } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); - effect.withAdditionalSubType(SubType.SPIRIT); - return effect.setTargetPointer(new FixedTarget(attached, game)).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java b/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java deleted file mode 100644 index bb9f5f62e56..00000000000 --- a/Mage.Sets/src/mage/cards/g/GhostlyCastigator.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GhostlyCastigator extends CardImpl { - - public GhostlyCastigator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When Ghostly Castigator enters the battlefield, you may shuffle up to three target cards from your graveyard into your library. - Ability ability = new EntersBattlefieldTriggeredAbility(new ShuffleIntoLibraryTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(0, 3)); - this.addAbility(ability); - - // If Ghostly Castigator would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GhostlyCastigator(final GhostlyCastigator card) { - super(card); - } - - @Override - public GhostlyCastigator copy() { - return new GhostlyCastigator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GhostlyKeybearer.java b/Mage.Sets/src/mage/cards/g/GhostlyKeybearer.java new file mode 100644 index 00000000000..c387627e364 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhostlyKeybearer.java @@ -0,0 +1,91 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +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.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +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 GhostlyKeybearer extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ROOM); + + public GhostlyKeybearer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever this creature deals combat damage to a player, unlock a locked door of up to one target Room you control. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new GhostlyKeybearerEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + } + + private GhostlyKeybearer(final GhostlyKeybearer card) { + super(card); + } + + @Override + public GhostlyKeybearer copy() { + return new GhostlyKeybearer(this); + } +} + +class GhostlyKeybearerEffect extends OneShotEffect { + + GhostlyKeybearerEffect() { + super(Outcome.Benefit); + staticText = "unlock a locked door of up to one target Room you control"; + } + + private GhostlyKeybearerEffect(final GhostlyKeybearerEffect effect) { + super(effect); + } + + @Override + public GhostlyKeybearerEffect copy() { + return new GhostlyKeybearerEffect(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.isLeftDoorUnlocked() && !permanent.isRightDoorUnlocked()) { + return false; + } + boolean unlockLeft; + if (!permanent.isLeftDoorUnlocked() && permanent.isRightDoorUnlocked()) { + unlockLeft = true; + } else if (permanent.isLeftDoorUnlocked() && !permanent.isRightDoorUnlocked()) { + unlockLeft = false; + } else { + unlockLeft = player.chooseUse( + Outcome.Neutral, "Unlock the left door or the right door?", + null, "Left", "Right", source, game + ); + } + return permanent.unlockDoor(game, source, unlockLeft); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiantFly.java b/Mage.Sets/src/mage/cards/g/GiantFly.java new file mode 100644 index 00000000000..2ef7ffb7fa2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiantFly.java @@ -0,0 +1,45 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +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.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GiantFly extends CardImpl { + + public GiantFly(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you sacrifice another permanent, this creature gets +1/+0 until end of turn. + this.addAbility(new SacrificePermanentTriggeredAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), StaticFilters.FILTER_ANOTHER_PERMANENT + )); + } + + private GiantFly(final GiantFly card) { + super(card); + } + + @Override + public GiantFly copy() { + return new GiantFly(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GibberingFiend.java b/Mage.Sets/src/mage/cards/g/GibberingFiend.java index 0fe87e51653..e119ecfb373 100644 --- a/Mage.Sets/src/mage/cards/g/GibberingFiend.java +++ b/Mage.Sets/src/mage/cards/g/GibberingFiend.java @@ -35,7 +35,7 @@ public final class GibberingFiend extends CardImpl { // Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, // Gibbering Fiend deals 1 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.OPPONENT, new DamageTargetEffect(1, true, "that player"), false + TargetController.OPPONENT, new DamageTargetEffect(1).withTargetDescription("that player"), false ).withInterveningIf(DeliriumCondition.instance).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); } diff --git a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java deleted file mode 100644 index a1158494564..00000000000 --- a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java +++ /dev/null @@ -1,141 +0,0 @@ -package mage.cards.g; - -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.RequirementEffect; -import mage.abilities.effects.common.PreventAllDamageToSourceEffect; -import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.custom.CreatureToken; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetOpponentsCreaturePermanent; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class GideonBattleForged extends CardImpl { - - public GideonBattleForged(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GIDEON); - - this.color.setWhite(true); - - this.nightCard = true; - - this.setStartingLoyalty(3); - - // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. - Ability ability = new LoyaltyAbility(new GideonBattleForgedEffect(), 2); - ability.addTarget(new TargetOpponentsCreaturePermanent(0, 1)); - this.addAbility(ability); - - // +1: Until your next turn, target creature gains indestructible. Untap that creature. - ability = new LoyaltyAbility(new GainAbilityTargetEffect( - IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn - ).setText("Until your next turn, target creature gains indestructible"), 1); - ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); - - // 0: Until end of turn, Gideon, Battle-Forged becomes a 4/4 Human Soldier creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn. - ability = new LoyaltyAbility(new BecomesCreatureSourceEffect(new CreatureToken( - 4, 4, "4/4 Human Soldier creature " + - "with indestructible", SubType.HUMAN, SubType.SOLDIER - ).withAbility(IndestructibleAbility.getInstance()), CardType.PLANESWALKER, Duration.EndOfTurn), 0); - ability.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn) - .setText("Prevent all damage that would be dealt to him this turn")); - this.addAbility(ability); - } - - private GideonBattleForged(final GideonBattleForged card) { - super(card); - } - - @Override - public GideonBattleForged copy() { - return new GideonBattleForged(this); - } -} - -class GideonBattleForgedEffect extends RequirementEffect { - - protected MageObjectReference targetPermanentReference; - - GideonBattleForgedEffect() { - super(Duration.Custom); - staticText = "up to one target creature an opponent controls attacks {this} during its controller's next turn if able"; - } - - private GideonBattleForgedEffect(final GideonBattleForgedEffect effect) { - super(effect); - this.targetPermanentReference = effect.targetPermanentReference; - } - - @Override - public GideonBattleForgedEffect copy() { - return new GideonBattleForgedEffect(this); - } - - @Override - public boolean isInactive(Ability source, Game game) { - if (targetPermanentReference == null) { - return true; - } - Permanent targetPermanent = targetPermanentReference.getPermanent(game); - if (targetPermanent == null) { - return true; - } - return game.getTurnPhaseType() == TurnPhase.END && this.isYourNextTurn(game); // discard on end of their next turn - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (getTargetPointer().getFirst(game, source) == null) { - discard(); - } else { - targetPermanentReference = new MageObjectReference(getTargetPointer().getFirst(game, source), game); - } - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - if (!permanent.getId().equals(getTargetPointer().getFirst(game, source)) - || !game.isActivePlayer(permanent.getControllerId())) { - return false; - } - Permanent planeswalker = source.getSourcePermanentIfItStillExists(game); - if (planeswalker == null) { - discard(); - return false; - } - return true; - } - - @Override - public UUID mustAttackDefender(Ability source, Game game) { - return source.getSourceId(); - } - - @Override - public boolean mustAttack(Game game) { - return true; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GideonsIntervention.java b/Mage.Sets/src/mage/cards/g/GideonsIntervention.java index c0e02db3487..3e6e91f0681 100644 --- a/Mage.Sets/src/mage/cards/g/GideonsIntervention.java +++ b/Mage.Sets/src/mage/cards/g/GideonsIntervention.java @@ -15,13 +15,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.util.CardUtil; @@ -118,19 +114,6 @@ class GideonsInterventionPreventAllDamageEffect extends PreventionEffectImpl { public GideonsInterventionPreventAllDamageEffect copy() { return new GideonsInterventionPreventAllDamageEffect(this); } - - @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 damage = event.getAmount(); - event.setAmount(0); - game.informPlayers("Damage has been prevented: " + damage); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { MageObject object = game.getObject(event.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java index 88b3ff747e2..a50cad504ac 100644 --- a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java +++ b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java @@ -1,20 +1,11 @@ package mage.cards.g; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryForFourDifferentCardsEffect; 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.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; -import mage.target.common.TargetCardWithDifferentNameInLibrary; +import mage.constants.PutCards; +import mage.filter.StaticFilters; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -28,7 +19,9 @@ public final class GiftsUngiven extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); // 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 your library. - this.getSpellAbility().addEffect(new GiftsUngivenEffect()); + this.getSpellAbility().addEffect(new SearchLibraryForFourDifferentCardsEffect( + StaticFilters.FILTER_CARD_CARDS, PutCards.HAND, true + )); this.getSpellAbility().addTarget(new TargetOpponent()); } @@ -41,57 +34,3 @@ public final class GiftsUngiven extends CardImpl { return new GiftsUngiven(this); } } - -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"; - } - - private GiftsUngivenEffect(final GiftsUngivenEffect effect) { - super(effect); - } - - @Override - public GiftsUngivenEffect copy() { - return new GiftsUngivenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player == null || opponent == null) { - return false; - } - 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); - } - player.revealCards(source, cards, game); - - 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, source, 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/g/GitaxianMindstinger.java b/Mage.Sets/src/mage/cards/g/GitaxianMindstinger.java deleted file mode 100644 index dbd1fe8fcbb..00000000000 --- a/Mage.Sets/src/mage/cards/g/GitaxianMindstinger.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.DeathtouchAbility; -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 GitaxianMindstinger extends CardImpl { - - public GitaxianMindstinger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Gitaxian Mindstinger deals combat damage to a player or battle, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility(new DrawCardSourceControllerEffect(1),false)); - } - - private GitaxianMindstinger(final GitaxianMindstinger card) { - super(card); - } - - @Override - public GitaxianMindstinger copy() { - return new GitaxianMindstinger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GitaxianSpellstalker.java b/Mage.Sets/src/mage/cards/g/GitaxianSpellstalker.java deleted file mode 100644 index 787c07ab3d4..00000000000 --- a/Mage.Sets/src/mage/cards/g/GitaxianSpellstalker.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.keyword.ProwessAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.WardAbility; -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 GitaxianSpellstalker extends CardImpl { - - public GitaxianSpellstalker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.JACKAL); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); - - // Prowess - this.addAbility(new ProwessAbility()); - - // Prowess - this.addAbility(new ProwessAbility()); - } - - private GitaxianSpellstalker(final GitaxianSpellstalker card) { - super(card); - } - - @Override - public GitaxianSpellstalker copy() { - return new GitaxianSpellstalker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GixianInfiltrator.java b/Mage.Sets/src/mage/cards/g/GixianInfiltrator.java index 765dc60b4e5..741efdfca77 100644 --- a/Mage.Sets/src/mage/cards/g/GixianInfiltrator.java +++ b/Mage.Sets/src/mage/cards/g/GixianInfiltrator.java @@ -8,8 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import java.util.UUID; @@ -18,12 +17,6 @@ import java.util.UUID; */ public final class GixianInfiltrator extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public GixianInfiltrator(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -34,7 +27,7 @@ public final class GixianInfiltrator extends CardImpl { // Whenever you sacrifice another permanent, put a +1/+1 counter on Gixian Infiltrator. this.addAbility(new SacrificePermanentTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT )); } diff --git a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java index ca9d183bce6..ff55c579e02 100644 --- a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java +++ b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java @@ -21,6 +21,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.LinkedList; import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -81,11 +82,11 @@ class GlamerSpinnersEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetPermanent == null || targetPermanent - .getAttachments() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .noneMatch(p -> p.hasSubtype(SubType.AURA, game))) { + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .noneMatch(p -> p.hasSubtype(SubType.AURA, game))) { return false; } FilterPermanent filter = new FilterPermanent( @@ -94,7 +95,7 @@ class GlamerSpinnersEffect extends OneShotEffect { .map(Controllable::getControllerId) .map(game::getPlayer) .map(Player::getName) - .map(s -> " controlled by" + s) + .map(s -> " controlled by " + s) .orElse("") ); filter.add(new ControllerIdPredicate(targetPermanent.getControllerId())); @@ -102,18 +103,23 @@ class GlamerSpinnersEffect extends OneShotEffect { if (!game.getBattlefield().contains(filter, source.getControllerId(), source, game, 1)) { return false; } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } TargetPermanent target = new TargetPermanent(filter); target.withNotTarget(true); - Optional.ofNullable(source) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .ifPresent(player -> player.choose(outcome, target, source, game)); + player.choose(Outcome.AIDontUseIt, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; } - for (UUID attachmentId : targetPermanent.getAttachments()) { - permanent.addAttachment(attachmentId, source, game); + // new list to avoid concurrent modification + for (UUID attachmentId : new LinkedList<>(targetPermanent.getAttachments())) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.hasSubtype(SubType.AURA, game)) { + permanent.addAttachment(attachmentId, source, game); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GlassworksShatteredYard.java b/Mage.Sets/src/mage/cards/g/GlassworksShatteredYard.java new file mode 100644 index 00000000000..ad65477e7bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlassworksShatteredYard.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.TargetController; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlassworksShatteredYard extends RoomCard { + + public GlassworksShatteredYard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{R}", "{4}{R}"); + + // Glassworks + // When you unlock this door, this Room deals 4 damage to target creature an opponent controls. + Ability ability = new UnlockThisDoorTriggeredAbility(new DamageTargetEffect(4), false, true); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.getLeftHalfCard().addAbility(ability); + + // Shattered Yard + // At the beginning of your end step, this Room deals 1 damage to each opponent. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new DamagePlayersEffect(1, TargetController.OPPONENT))); + } + + private GlassworksShatteredYard(final GlassworksShatteredYard card) { + super(card); + } + + @Override + public GlassworksShatteredYard copy() { + return new GlassworksShatteredYard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GliderStaff.java b/Mage.Sets/src/mage/cards/g/GliderStaff.java new file mode 100644 index 00000000000..f3a47ca0d51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GliderStaff.java @@ -0,0 +1,54 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GliderStaff extends CardImpl { + + public GliderStaff(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When this Equipment enters, airbend up to one target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect()); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // Equipped creature gets +1/+1 and has flying. + ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has flying")); + this.addAbility(ability); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private GliderStaff(final GliderStaff card) { + super(card); + } + + @Override + public GliderStaff copy() { + return new GliderStaff(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlisteningGoremonger.java b/Mage.Sets/src/mage/cards/g/GlisteningGoremonger.java deleted file mode 100644 index aa682247428..00000000000 --- a/Mage.Sets/src/mage/cards/g/GlisteningGoremonger.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.common.SacrificeOpponentsEffect; -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 GlisteningGoremonger extends CardImpl { - - public GlisteningGoremonger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.DEVIL); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - // When Glistening Goremonger dies, each opponent sacrifices an artifact or creature. - this.addAbility(new DiesSourceTriggeredAbility(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE))); - } - - private GlisteningGoremonger(final GlisteningGoremonger card) { - super(card); - } - - @Override - public GlisteningGoremonger copy() { - return new GlisteningGoremonger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java b/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java deleted file mode 100644 index ad4fced764d..00000000000 --- a/Mage.Sets/src/mage/cards/g/GnarledGrovestrider.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -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.StaticFilters; - -import java.util.UUID; - -/** - * - * @author weirddan455 - */ -public class GnarledGrovestrider extends CardImpl { - - public GnarledGrovestrider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.TREEFOLK); - this.color.setGreen(true); - - // Back half of Dormant Grove - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(6); - - this.addAbility(VigilanceAbility.getInstance()); - - // Other creatures you control have vigilance. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURES, true - ))); - } - - private GnarledGrovestrider(final GnarledGrovestrider card) { - super(card); - } - - @Override - public GnarledGrovestrider copy() { - return new GnarledGrovestrider(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GnottvoldHermit.java b/Mage.Sets/src/mage/cards/g/GnottvoldHermit.java index f8410e520a0..c0902ea0a6e 100644 --- a/Mage.Sets/src/mage/cards/g/GnottvoldHermit.java +++ b/Mage.Sets/src/mage/cards/g/GnottvoldHermit.java @@ -1,33 +1,56 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessTargetEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 GnottvoldHermit extends CardImpl { +public final class GnottvoldHermit extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); + + static { + filter.add(AnotherPredicate.instance); + } public GnottvoldHermit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TROLL}, "{3}{G}", + "Chrome Host Hulk", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.TROLL}, "UG" + ); - this.subtype.add(SubType.TROLL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.c.ChromeHostHulk.class; + // Gnottvold Hermit + this.getLeftHalfCard().setPT(4, 4); // {5}{U/P}: Transform Gnottvold Hermit. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{U/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{U/P}"))); + + // Chrome Host Hulk + this.getRightHalfCard().setPT(5, 5); + + // Whenever Chrome Host Hulk attacks, up to one other target creature has base power and toughness 5/5 until end of turn. + Ability ability = new AttacksTriggeredAbility( + new SetBasePowerToughnessTargetEffect(5, 5, Duration.EndOfTurn) + ); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.getRightHalfCard().addAbility(ability); } private GnottvoldHermit(final GnottvoldHermit card) { diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfAncientWars.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfAncientWars.java index 01011d968ac..6640e0dd927 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfAncientWars.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfAncientWars.java @@ -1,22 +1,18 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DoWhenCostPaid; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; @@ -26,11 +22,6 @@ import java.util.UUID; */ public final class GoShintaiOfAncientWars extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public GoShintaiOfAncientWars(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{2}{R}"); @@ -44,13 +35,13 @@ public final class GoShintaiOfAncientWars extends CardImpl { // At the beginning of your end step, you may pay {1}. When you do, Go-Shintai of Ancient Wars deals X damage to target player or planeswalker, where X is the number of Shrines you control. ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new DamageTargetEffect(xValue), false, "{this} deals X damage to target " + - "player or planeswalker, where X is the number of Shrines you control" + new DamageTargetEffect(ShrinesYouControlCount.WHERE_X), false, "{this} deals X damage " + + "to target player or planeswalker, where X is the number of Shrines you control" ); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(new BeginningOfEndStepTriggeredAbility( new DoWhenCostPaid(ability, new GenericManaCost(1), "Pay {1}?") - ).addHint(hint)); + ).addHint(ShrinesYouControlCount.getHint())); } private GoShintaiOfAncientWars(final GoShintaiOfAncientWars card) { diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfBoundlessVigor.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfBoundlessVigor.java index 6c50c66c30e..6f3af4a118b 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfBoundlessVigor.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfBoundlessVigor.java @@ -1,16 +1,13 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,7 +15,6 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPermanent; import java.util.UUID; @@ -28,11 +24,7 @@ import java.util.UUID; */ public final class GoShintaiOfBoundlessVigor extends CardImpl { - private static final FilterPermanent filter - = new FilterPermanent(SubType.SHRINE, "Shrine"); - private static final DynamicValue xValue - = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.SHRINE)); - private static final Hint hint = new ValueHint("Shrines you control", xValue); + private static final FilterPermanent filter = new FilterPermanent(SubType.SHRINE, "Shrine"); public GoShintaiOfBoundlessVigor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}"); @@ -46,15 +38,13 @@ public final class GoShintaiOfBoundlessVigor extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of your end step, you may pay {1}. When you do, put a +1/+1 counter on target Shrine for each Shrine you control. - ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new AddCountersTargetEffect( - CounterType.P1P1.createInstance(0), xValue - ), false - ); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(0), ShrinesYouControlCount.FOR_EACH + ), false); ability.addTarget(new TargetPermanent(filter)); this.addAbility(new BeginningOfEndStepTriggeredAbility(new DoWhenCostPaid( ability, new GenericManaCost(1), "Pay {1}?" - )).addHint(hint)); + )).addHint(ShrinesYouControlCount.getHint())); } private GoShintaiOfBoundlessVigor(final GoShintaiOfBoundlessVigor card) { diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java index 38c76716b3f..4a4fd0f0c5b 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java @@ -1,15 +1,13 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DoWhenCostPaid; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -58,7 +56,7 @@ public final class GoShintaiOfHiddenCruelty extends CardImpl { ability.addTarget(new TargetPermanent(filter)); this.addAbility(new BeginningOfEndStepTriggeredAbility( new DoWhenCostPaid(ability, new GenericManaCost(1), "Pay {1}?") - ).addHint(GoShintaiOfHiddenCrueltyPredicate.getHint())); + ).addHint(ShrinesYouControlCount.getHint())); } private GoShintaiOfHiddenCruelty(final GoShintaiOfHiddenCruelty card) { @@ -74,13 +72,6 @@ public final class GoShintaiOfHiddenCruelty extends CardImpl { enum GoShintaiOfHiddenCrueltyPredicate implements ObjectSourcePlayerPredicate { instance; private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SHRINE); - private static final Hint hint = new ValueHint( - "Shrines you control", new PermanentsOnBattlefieldCount(filter) - ); - - public static Hint getHint() { - return hint; - } @Override public boolean apply(ObjectSourcePlayer input, Game game) { diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfLostWisdom.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfLostWisdom.java index aee2e8ce8a9..efdf3706723 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfLostWisdom.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfLostWisdom.java @@ -1,22 +1,18 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.MillCardsTargetEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPlayer; import java.util.UUID; @@ -26,11 +22,6 @@ import java.util.UUID; */ public final class GoShintaiOfLostWisdom extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public GoShintaiOfLostWisdom(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{U}"); @@ -44,13 +35,13 @@ public final class GoShintaiOfLostWisdom extends CardImpl { // At the beginning of your end step, you may pay {1}. When you do, target player mills X cards, where X is the number of Shrines you control. ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new MillCardsTargetEffect(xValue), false, + new MillCardsTargetEffect(ShrinesYouControlCount.WHERE_X), false, "target player mills X cards, where X is the number of Shrines you control" ); ability.addTarget(new TargetPlayer()); this.addAbility(new BeginningOfEndStepTriggeredAbility(new DoWhenCostPaid( ability, new GenericManaCost(1), "Pay {1}?" - )).addHint(hint)); + )).addHint(ShrinesYouControlCount.getHint())); } private GoShintaiOfLostWisdom(final GoShintaiOfLostWisdom card) { diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfSharedPurpose.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfSharedPurpose.java index f565593f6bd..66c1398927c 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfSharedPurpose.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfSharedPurpose.java @@ -1,21 +1,17 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.SpiritToken; import java.util.UUID; @@ -25,11 +21,6 @@ import java.util.UUID; */ public final class GoShintaiOfSharedPurpose extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public GoShintaiOfSharedPurpose(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{3}{W}"); @@ -42,12 +33,9 @@ public final class GoShintaiOfSharedPurpose extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // At the beginning of your end step, you may pay {1}. If you do, create a 1/1 colorless Spirit creature token for each Shrine you control. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - new DoIfCostPaid( - new CreateTokenEffect(new SpiritToken(), xValue), - new GenericManaCost(1) - ) - ).addHint(hint)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DoIfCostPaid( + new CreateTokenEffect(new SpiritToken(), ShrinesYouControlCount.FOR_EACH), new GenericManaCost(1) + )).addHint(ShrinesYouControlCount.getHint())); } private GoShintaiOfSharedPurpose(final GoShintaiOfSharedPurpose card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinArtillery.java b/Mage.Sets/src/mage/cards/g/GoblinArtillery.java index 77b0946d7be..c5c19053734 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinArtillery.java +++ b/Mage.Sets/src/mage/cards/g/GoblinArtillery.java @@ -4,8 +4,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,8 +25,9 @@ public final class GoblinArtillery extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - ability.addEffect(new DamageControllerEffect(3).setText("and 3 damage to you")); + + // {T}: This creature deals 2 damage to any target and 3 damage to you. + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(2, 3), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinBlastRunner.java b/Mage.Sets/src/mage/cards/g/GoblinBlastRunner.java index b532381e56d..3371fa82418 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBlastRunner.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBlastRunner.java @@ -62,12 +62,9 @@ enum GoblinBlastRunnerCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - UUID player = source.getControllerId(); PermanentsSacrificedWatcher watcher = game.getState().getWatcher(PermanentsSacrificedWatcher.class); - if (watcher == null) { - return false; - } - return watcher.getThisTurnSacrificedPermanents(player) != null; + return watcher != null + && !watcher.getThisTurnSacrificedPermanents(source.getControllerId()).isEmpty(); } public static Hint getHint() { diff --git a/Mage.Sets/src/mage/cards/g/GoldForgeGarrison.java b/Mage.Sets/src/mage/cards/g/GoldForgeGarrison.java deleted file mode 100644 index 5fd3930da98..00000000000 --- a/Mage.Sets/src/mage/cards/g/GoldForgeGarrison.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.g; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.permanent.token.GoldForgeGarrisonGolemToken; - -/** - * - * @author LevelX2 - */ -public final class GoldForgeGarrison extends CardImpl { - - public GoldForgeGarrison(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // (Transforms from Golden Guardian.) - - // {T}: Add two mana of any one color. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost())); - - // {4}, {T}: Create a 4/4 colorless Golem artifact creature token. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new GoldForgeGarrisonGolemToken(), 1), new GenericManaCost(4)); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - - } - - private GoldForgeGarrison(final GoldForgeGarrison card) { - super(card); - } - - @Override - public GoldForgeGarrison copy() { - return new GoldForgeGarrison(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java b/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java index 5b81a1d8090..2c99ca8339b 100644 --- a/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java +++ b/Mage.Sets/src/mage/cards/g/GoldbugHumanitysAlly.java @@ -1,55 +1,76 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.PreventAllDamageToAllEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import java.util.Objects; import java.util.UUID; /** * @author TheElk801 */ -public final class GoldbugHumanitysAlly extends CardImpl { +public final class GoldbugHumanitysAlly extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.HUMAN, "attacking Humans you control"); + private static final FilterSpell humanSpellFilter = new FilterSpell("Human spells"); + static { filter.add(AttackingPredicate.instance); + humanSpellFilter.add(SubType.HUMAN.getPredicate()); } public GoldbugHumanitysAlly(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{1}{W}{U}", + "Goldbug, Scrappy Scout", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "WU" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.g.GoldbugScrappyScout.class; + // Goldbug, Humanity's Ally + this.getLeftHalfCard().setPT(3, 3); // More Than Meets the Eye {W}{U} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{W}{U}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{W}{U}")); // Prevent all combat damage that would be dealt to attacking Humans you control. - this.addAbility(new SimpleStaticAbility(new PreventAllDamageToAllEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new PreventAllDamageToAllEffect( Duration.WhileOnBattlefield, filter, true ))); // Whenever you cast your second spell each turn, convert Goldbug. - this.addAbility(new CastSecondSpellTriggeredAbility(new TransformSourceEffect().setText("convert {this}"))); + this.getLeftHalfCard().addAbility(new CastSecondSpellTriggeredAbility(new TransformSourceEffect().setText("convert {this}"))); + + // Goldbug, Scrappy Scout + this.getRightHalfCard().setPT(1, 3); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Human spells you control can't be countered. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect( + humanSpellFilter, Duration.WhileOnBattlefield + ))); + + // Whenever Goldbug and at least one Human attack, draw a card and convert Goldbug. + this.getRightHalfCard().addAbility(new GoldbugScrappyScoutTriggeredAbility()); } private GoldbugHumanitysAlly(final GoldbugHumanitysAlly card) { @@ -61,3 +82,45 @@ public final class GoldbugHumanitysAlly extends CardImpl { return new GoldbugHumanitysAlly(this); } } + +class GoldbugScrappyScoutTriggeredAbility extends TriggeredAbilityImpl { + + GoldbugScrappyScoutTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); + this.addEffect(new TransformSourceEffect()); + } + + private GoldbugScrappyScoutTriggeredAbility(final GoldbugScrappyScoutTriggeredAbility ability) { + super(ability); + } + + @Override + public GoldbugScrappyScoutTriggeredAbility copy() { + return new GoldbugScrappyScoutTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game + .getCombat() + .getAttackers() + .contains(getSourceId()) + && game + .getCombat() + .getAttackers() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.hasSubtype(SubType.HUMAN, game)); + } + + @Override + public String getRule() { + return "Whenever {this} and at least one Human attack, draw a card and convert {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java b/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java deleted file mode 100644 index 4cd192a781e..00000000000 --- a/Mage.Sets/src/mage/cards/g/GoldbugScrappyScout.java +++ /dev/null @@ -1,104 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CantBeCounteredControlledEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.events.GameEvent; - -import java.util.Objects; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GoldbugScrappyScout extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("Human spells"); - - static { - filter.add(SubType.HUMAN.getPredicate()); - } - - public GoldbugScrappyScout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Human spells you control can't be countered. - this.addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect( - filter, Duration.WhileOnBattlefield - ))); - - // Whenever Goldbug and at least one Human attack, draw a card and convert Goldbug. - this.addAbility(new GoldbugScrappyScoutTriggeredAbility()); - } - - private GoldbugScrappyScout(final GoldbugScrappyScout card) { - super(card); - } - - @Override - public GoldbugScrappyScout copy() { - return new GoldbugScrappyScout(this); - } -} - -class GoldbugScrappyScoutTriggeredAbility extends TriggeredAbilityImpl { - - GoldbugScrappyScoutTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); - this.addEffect(new TransformSourceEffect()); - } - - private GoldbugScrappyScoutTriggeredAbility(final GoldbugScrappyScoutTriggeredAbility ability) { - super(ability); - } - - @Override - public GoldbugScrappyScoutTriggeredAbility copy() { - return new GoldbugScrappyScoutTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return game - .getCombat() - .getAttackers() - .contains(getSourceId()) - && game - .getCombat() - .getAttackers() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .anyMatch(permanent -> permanent.hasSubtype(SubType.HUMAN, game)); - } - - @Override - public String getRule() { - return "Whenever {this} and at least one Human attack, draw a card and convert {this}."; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java index d30b0a5cf7a..c04f609ad9e 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java +++ b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java @@ -1,23 +1,27 @@ package mage.cards.g; -import mage.MageInt; 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.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.GoldForgeGarrisonGolemToken; import mage.players.Player; import mage.target.TargetPermanent; @@ -26,26 +30,35 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class GoldenGuardian extends CardImpl { +public final class GoldenGuardian extends TransformingDoubleFacedCard { public GoldenGuardian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "{4}", + "Gold-Forge Garrison", + new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.g.GoldForgeGarrison.class; + // Golden Guardian + this.getLeftHalfCard().setPT(4, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {2}: Golden Guardian fights another target creature you control. When Golden Guardian dies this turn, return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new FightTargetSourceEffect(), new GenericManaCost(2)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new GoldenGuardianDelayedTriggeredAbility(), false)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Gold-Forge Garrison + // {T}: Add two mana of any one color. + this.getRightHalfCard().addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost())); + + // {4}, {T}: Create a 4/4 colorless Golem artifact creature token. + Ability backAbility = new SimpleActivatedAbility(new CreateTokenEffect(new GoldForgeGarrisonGolemToken(), 1), new GenericManaCost(4)); + backAbility.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(backAbility); } private GoldenGuardian(final GoldenGuardian card) { @@ -60,7 +73,7 @@ public final class GoldenGuardian extends CardImpl { class GoldenGuardianDelayedTriggeredAbility extends DelayedTriggeredAbility { - public GoldenGuardianDelayedTriggeredAbility() { + GoldenGuardianDelayedTriggeredAbility() { super(new GoldenGuardianReturnTransformedEffect(), Duration.EndOfTurn); setTriggerPhrase("When {this} dies this turn, "); } diff --git a/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java b/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java index 93f24e52fe4..7466457aa59 100644 --- a/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java +++ b/Mage.Sets/src/mage/cards/g/GornogTheRedReaper.java @@ -20,7 +20,7 @@ import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -61,7 +61,7 @@ public final class GornogTheRedReaper extends CardImpl { Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility( new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.COWARD).setText("target creature that player controls becomes a Coward"), filterWarrior, SetTargetPointer.PLAYER); - ability.addTarget(new TargetPermanent()); + ability.addTarget(new TargetCreaturePermanent()); ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GranGran.java b/Mage.Sets/src/mage/cards/g/GranGran.java new file mode 100644 index 00000000000..74a1d6538d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GranGran.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.decorator.ConditionalCostModificationEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +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 GranGran extends CardImpl { + + public GranGran(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever Gran-Gran becomes tapped, draw a card, then discard a card. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); + + // Noncreature spells you cast cost {1} less to cast as long as there are three or more Lesson cards in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalCostModificationEffect( + new SpellsCostReductionControllerEffect(StaticFilters.FILTER_CARD_NON_CREATURE, 1), + LessonsInGraveCondition.THREE, "noncreature spells you cast cost {1} less to cast as long as " + + "there are three or more Lesson cards in your graveyard" + )).addHint(LessonsInGraveCondition.getHint())); + } + + private GranGran(final GranGran card) { + super(card); + } + + @Override + public GranGran copy() { + return new GranGran(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrandEntrywayElegantRotunda.java b/Mage.Sets/src/mage/cards/g/GrandEntrywayElegantRotunda.java new file mode 100644 index 00000000000..2df43f1745e --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrandEntrywayElegantRotunda.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.counters.CounterType; +import mage.game.permanent.token.GlimmerToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrandEntrywayElegantRotunda extends RoomCard { + + public GrandEntrywayElegantRotunda(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{1}{W}", "{2}{W}"); + + // Grand Entryway + // When you unlock this door, create a 1/1 white Glimmer enchantment creature token. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new CreateTokenEffect(new GlimmerToken()), false, true)); + + // Elegant Rotunda + // When you unlock this door, put a +1/+1 counter on each of up to two target creatures. + Ability ability = new UnlockThisDoorTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false, false); + ability.addTarget(new TargetCreaturePermanent(0, 2)); + this.getRightHalfCard().addAbility(ability); + } + + private GrandEntrywayElegantRotunda(final GrandEntrywayElegantRotunda card) { + super(card); + } + + @Override + public GrandEntrywayElegantRotunda copy() { + return new GrandEntrywayElegantRotunda(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrandmotherRaviSengir.java b/Mage.Sets/src/mage/cards/g/GrandmotherRaviSengir.java deleted file mode 100644 index c535576b30f..00000000000 --- a/Mage.Sets/src/mage/cards/g/GrandmotherRaviSengir.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.effects.common.GainLifeEffect; -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.SuperType; -import mage.counters.CounterType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GrandmotherRaviSengir extends CardImpl { - - public GrandmotherRaviSengir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever a creature an opponent controls dies, put a +1/+1 counter on Grandmother Ravi Sengir and you gain 1 life. - Ability ability = new DiesCreatureTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE - ); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private GrandmotherRaviSengir(final GrandmotherRaviSengir card) { - super(card); - } - - @Override - public GrandmotherRaviSengir copy() { - return new GrandmotherRaviSengir(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GrangerGuildmage.java b/Mage.Sets/src/mage/cards/g/GrangerGuildmage.java index aa45d3eb1c8..c7dbd57ec8f 100644 --- a/Mage.Sets/src/mage/cards/g/GrangerGuildmage.java +++ b/Mage.Sets/src/mage/cards/g/GrangerGuildmage.java @@ -1,25 +1,23 @@ - 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.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; 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.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author fireshoes @@ -34,9 +32,8 @@ public final class GrangerGuildmage extends CardImpl { this.toughness = new MageInt(1); // {R}, {tap}: Granger Guildmage deals 1 damage to any target and 1 damage to you. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{R}")); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(1, 1), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new DamageControllerEffect(1).setText("and 1 damage to you")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GraspingShadows.java b/Mage.Sets/src/mage/cards/g/GraspingShadows.java index 9297ca57c2d..c73dc3f5752 100644 --- a/Mage.Sets/src/mage/cards/g/GraspingShadows.java +++ b/Mage.Sets/src/mage/cards/g/GraspingShadows.java @@ -2,18 +2,26 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.BlackManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; import java.util.UUID; @@ -21,14 +29,18 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class GraspingShadows extends CardImpl { +public final class GraspingShadows extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.DREAD, 3); public GraspingShadows(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); - this.secondSideCardClazz = mage.cards.s.ShadowsLair.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{B}", + "Shadows' Lair", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, "" + ); + // Grasping Shadows // Whenever a creature you control attacks alone, it gains deathtouch and lifelink until end of turn. Put a dread counter on Grasping Shadows. Then if there are three or more dread counters on it, transform it. Ability ability = new AttacksAloneControlledTriggeredAbility( new GainAbilityTargetEffect(DeathtouchAbility.getInstance()) @@ -42,8 +54,20 @@ public final class GraspingShadows extends CardImpl { new TransformSourceEffect(), condition, "Then if there are three or more dread counters on it, transform it" )); - this.addAbility(new TransformAbility()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Shadows' Lair + // {T}: Add {B}. + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // {B}, {T}, Remove a dread counter from Shadows' Lair: You draw a card and you lose 1 life. + Ability backAbility = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1, true), new ManaCostsImpl<>("{B}") + ); + backAbility.addCost(new TapSourceCost()); + backAbility.addCost(new RemoveCountersSourceCost(CounterType.DREAD.createInstance())); + backAbility.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(backAbility); } private GraspingShadows(final GraspingShadows card) { diff --git a/Mage.Sets/src/mage/cards/g/GraveyardGlutton.java b/Mage.Sets/src/mage/cards/g/GraveyardGlutton.java deleted file mode 100644 index 5d6f60ee957..00000000000 --- a/Mage.Sets/src/mage/cards/g/GraveyardGlutton.java +++ /dev/null @@ -1,99 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.WardAbility; -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.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GraveyardGlutton extends CardImpl { - - public GraveyardGlutton(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Ward—Discard a card. - this.addAbility(new WardAbility(new DiscardCardCost(), false)); - - // Whenever Graveyard Glutton enters the battlefield or attacks, exile up to two target cards from graveyards. For each creature card exiled this way, each opponent loses 1 life and you gain 1 life. - Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GraveyardGluttonEffect()); - ability.addTarget(new TargetCardInGraveyard(0, 2)); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private GraveyardGlutton(final GraveyardGlutton card) { - super(card); - } - - @Override - public GraveyardGlutton copy() { - return new GraveyardGlutton(this); - } -} - -class GraveyardGluttonEffect extends OneShotEffect { - - GraveyardGluttonEffect() { - super(Outcome.Benefit); - staticText = "exile up to two target cards from graveyards. " + - "For each creature card exiled this way, each opponent loses 1 life and you gain 1 life"; - } - - private GraveyardGluttonEffect(final GraveyardGluttonEffect effect) { - super(effect); - } - - @Override - public GraveyardGluttonEffect copy() { - return new GraveyardGluttonEffect(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); - int amount = cards.count(StaticFilters.FILTER_CARD_CREATURE, game); - if (amount < 1) { - return true; - } - player.gainLife(amount, game, source); - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - opponent.loseLife(amount, game, source, false); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GraveyardTrespasser.java b/Mage.Sets/src/mage/cards/g/GraveyardTrespasser.java index 1e3f1f865e2..7ad4f57b6ac 100644 --- a/Mage.Sets/src/mage/cards/g/GraveyardTrespasser.java +++ b/Mage.Sets/src/mage/cards/g/GraveyardTrespasser.java @@ -1,16 +1,16 @@ package mage.cards.g; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -25,27 +25,42 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class GraveyardTrespasser extends CardImpl { +public final class GraveyardTrespasser extends TransformingDoubleFacedCard { public GraveyardTrespasser(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{B}", + "Graveyard Glutton", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.g.GraveyardGlutton.class; + // Graveyard Trespasser + this.getLeftHalfCard().setPT(3, 3); // Ward—Discard a card. - this.addAbility(new WardAbility(new DiscardCardCost(), false)); + this.getLeftHalfCard().addAbility(new WardAbility(new DiscardCardCost(), false)); // Whenever Graveyard Trespasser enters the battlefield or attacks, exile up to one target card from a graveyard. If a creature card was exiled this way, each opponent loses 1 life and you gain 1 life. Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GraveyardTrespasserEffect()); ability.addTarget(new TargetCardInGraveyard(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Graveyard Glutton + this.getRightHalfCard().setPT(4, 4); + + // Ward—Discard a card. + this.getRightHalfCard().addAbility(new WardAbility(new DiscardCardCost(), false)); + + // Whenever Graveyard Glutton enters the battlefield or attacks, exile up to two target cards from graveyards. For each creature card exiled this way, each opponent loses 1 life and you gain 1 life. + Ability backAbility = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GraveyardGluttonEffect()); + backAbility.addTarget(new TargetCardInGraveyard(0, 2)); + this.getRightHalfCard().addAbility(backAbility); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private GraveyardTrespasser(final GraveyardTrespasser card) { @@ -98,3 +113,43 @@ class GraveyardTrespasserEffect extends OneShotEffect { return true; } } + +class GraveyardGluttonEffect extends OneShotEffect { + + GraveyardGluttonEffect() { + super(Outcome.Benefit); + staticText = "exile up to two target cards from graveyards. " + + "For each creature card exiled this way, each opponent loses 1 life and you gain 1 life"; + } + + private GraveyardGluttonEffect(final GraveyardGluttonEffect effect) { + super(effect); + } + + @Override + public GraveyardGluttonEffect copy() { + return new GraveyardGluttonEffect(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); + int amount = cards.count(StaticFilters.FILTER_CARD_CREATURE, game); + if (amount < 1) { + return true; + } + player.gainLife(amount, game, source); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + opponent.loseLife(amount, game, source, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GreatDivideGuide.java b/Mage.Sets/src/mage/cards/g/GreatDivideGuide.java new file mode 100644 index 00000000000..ea4dda96d9a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GreatDivideGuide.java @@ -0,0 +1,54 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.mana.AnyColorManaAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GreatDivideGuide extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("each land and Ally"); + + static { + filter.add(Predicates.or( + CardType.LAND.getPredicate(), + SubType.ALLY.getPredicate() + )); + } + + public GreatDivideGuide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Each land and Ally you control has "{T} : Add one mana of any color." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new AnyColorManaAbility(), Duration.WhileOnBattlefield, filter + ))); + } + + private GreatDivideGuide(final GreatDivideGuide card) { + super(card); + } + + @Override + public GreatDivideGuide copy() { + return new GreatDivideGuide(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GreenhouseRicketyGazebo.java b/Mage.Sets/src/mage/cards/g/GreenhouseRicketyGazebo.java new file mode 100644 index 00000000000..f91689a14c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GreenhouseRicketyGazebo.java @@ -0,0 +1,48 @@ +package mage.cards.g; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.MillThenPutInHandEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GreenhouseRicketyGazebo extends RoomCard { + + public GreenhouseRicketyGazebo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{G}", "{3}{G}"); + + // Greenhouse + // Lands you control have "{T}: Add one mana of any color." + ContinuousEffect effect = new GainAbilityControlledEffect( + new AnyColorManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS, false + ); + effect.addDependedToType(DependencyType.BecomeNonbasicLand); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(effect)); + + // Rickety Gazebo + // When you unlock this door, mill four cards, then return up to two permanent cards from among them to your hand. + this.getRightHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new MillThenPutInHandEffect( + 4, StaticFilters.FILTER_CARD_PERMANENTS, null, true, 2 + ), false, false)); + } + + private GreenhouseRicketyGazebo(final GreenhouseRicketyGazebo card) { + super(card); + } + + @Override + public GreenhouseRicketyGazebo copy() { + return new GreenhouseRicketyGazebo(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrimReapersSprint.java b/Mage.Sets/src/mage/cards/g/GrimReapersSprint.java index 10efdaf4a85..d0f66b8037c 100644 --- a/Mage.Sets/src/mage/cards/g/GrimReapersSprint.java +++ b/Mage.Sets/src/mage/cards/g/GrimReapersSprint.java @@ -59,7 +59,7 @@ public final class GrimReapersSprint extends CardImpl { "untap each creature you control" ), false ); - triggeredAbility.addEffect(new ConditionalOneShotEffect(new AdditionalCombatPhaseEffect(), IsMainPhaseCondition.YOUR, "If it's your main phase, there is an additional combat phase after this phase.")); + triggeredAbility.addEffect(new ConditionalOneShotEffect(new AdditionalCombatPhaseEffect(), IsMainPhaseCondition.YOURS, "If it's your main phase, there is an additional combat phase after this phase.")); this.addAbility(triggeredAbility); // Enchanted creature gets +2/+2 and has haste. @@ -110,4 +110,4 @@ class GrimReapersSprintCostModificationEffect extends CostModificationEffectImpl public GrimReapersSprintCostModificationEffect copy() { return new GrimReapersSprintCostModificationEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java b/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java index bbc81909820..4e5d938eae5 100644 --- a/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java +++ b/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java @@ -1,61 +1,71 @@ - package mage.cards.g; -import java.util.UUID; -import mage.MageInt; +import mage.MageObject; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; -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.TransformedPredicate; +import java.util.UUID; /** - * * @author Saga */ -public final class GrimlockDinobotLeader extends CardImpl{ - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Dinosaurs and Vehicles"); +public final class GrimlockDinobotLeader extends TransformingDoubleFacedCard { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Dinosaurs and Vehicles you control"); static { - filter.add(Predicates.or(SubType.DINOSAUR.getPredicate(), SubType.VEHICLE.getPredicate())); + filter.add(Predicates.or( + SubType.DINOSAUR.getPredicate(), + SubType.VEHICLE.getPredicate()) + ); } - + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Transformers creatures"); static { filter2.add(Predicates.not(SubType.DINOSAUR.getPredicate())); filter2.add(Predicates.not(SubType.VEHICLE.getPredicate())); filter2.add(Predicates.or(new AbilityPredicate(TransformAbility.class), TransformedPredicate.instance)); } - - public GrimlockDinobotLeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT,CardType.CREATURE}, "{1}{R}{G}{W}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AUTOBOT); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.g.GrimlockFerociousKing.class; + public GrimlockDinobotLeader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.AUTOBOT}, "{1}{R}{G}{W}", + "Grimlock, Ferocious King", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.DINOSAUR}, "RGW" + ); + + // Grimlock, Dinobot Leader + this.getLeftHalfCard().setPT(4, 4); // Dinosaurs, Vehicles and other Transformers creatures you control get +2/+0. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield, filter, false))); - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield, filter2, true))); - + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield, filter, false))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield, filter2, true))); + // {2}: Grimlock, Dinobot Leader becomes Grimlock, Ferocious King. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{2}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{2}"))); + + // Grimlock, Ferocious King + this.getRightHalfCard().setPT(8, 8); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // {2}: Grimlock, Ferocious King becomes Grimlock, Dinobot Leader. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{2}"))); } private GrimlockDinobotLeader(final GrimlockDinobotLeader card) { @@ -66,5 +76,4 @@ public final class GrimlockDinobotLeader extends CardImpl{ public GrimlockDinobotLeader copy() { return new GrimlockDinobotLeader(this); } - } diff --git a/Mage.Sets/src/mage/cards/g/GrimlockFerociousKing.java b/Mage.Sets/src/mage/cards/g/GrimlockFerociousKing.java deleted file mode 100644 index f24ff1b75e6..00000000000 --- a/Mage.Sets/src/mage/cards/g/GrimlockFerociousKing.java +++ /dev/null @@ -1,53 +0,0 @@ - -package mage.cards.g; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; - -/** - * - * @author Saga - */ -public final class GrimlockFerociousKing extends CardImpl{ - - public GrimlockFerociousKing(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - this.color.setRed(true); - this.color.setGreen(true); - this.color.setWhite(true); - - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // {2}: Grimlock, Ferocious King becomes Grimlock, Dinobot Leader. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{2}"))); - } - - private GrimlockFerociousKing(final GrimlockFerociousKing card) { - super(card); - } - - @Override - public GrimlockFerociousKing copy() { - return new GrimlockFerociousKing(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/g/GrislyAnglerfish.java b/Mage.Sets/src/mage/cards/g/GrislyAnglerfish.java deleted file mode 100644 index a8eace0c588..00000000000 --- a/Mage.Sets/src/mage/cards/g/GrislyAnglerfish.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; -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 fireshoes - */ -public final class GrislyAnglerfish extends CardImpl { - - public GrislyAnglerfish(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.FISH); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {6}: Creatures your opponents control attack this turn if able. - this.addAbility(new SimpleActivatedAbility(new AttacksIfAbleAllEffect( - StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn - ), new ManaCostsImpl<>("{6}"))); - } - - private GrislyAnglerfish(final GrislyAnglerfish card) { - super(card); - } - - @Override - public GrislyAnglerfish copy() { - return new GrislyAnglerfish(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GristThePlagueSwarm.java b/Mage.Sets/src/mage/cards/g/GristThePlagueSwarm.java deleted file mode 100644 index 41a53240019..00000000000 --- a/Mage.Sets/src/mage/cards/g/GristThePlagueSwarm.java +++ /dev/null @@ -1,163 +0,0 @@ -package mage.cards.g; - -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentCard; -import mage.game.permanent.token.IzoniInsectToken; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.targetpointer.FixedTargets; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author Susucr - */ -public final class GristThePlagueSwarm extends CardImpl { - - public GristThePlagueSwarm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GRIST); - this.setStartingLoyalty(3); - - this.color.setBlack(true); - this.color.setGreen(true); - this.nightCard = true; - - // +1: Create a 1/1 black and green Insect creature token, then mill two cards. Put a deathtouch counter on the token if a black card was milled this way. - this.addAbility(new LoyaltyAbility(new GristThePlagueSwarmPlus1Effect(), 1)); - - // -2: Destroy target artifact or enchantment. - Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -2); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); - this.addAbility(ability); - - // -6: For each creature card in your graveyard, create a token that's a copy of it, except it's a 1/1 black and green Insect. - this.addAbility(new LoyaltyAbility(new GristThePlagueSwarmMinus6Effect(), -6)); - } - - private GristThePlagueSwarm(final GristThePlagueSwarm card) { - super(card); - } - - @Override - public GristThePlagueSwarm copy() { - return new GristThePlagueSwarm(this); - } -} - -class GristThePlagueSwarmPlus1Effect extends OneShotEffect { - - GristThePlagueSwarmPlus1Effect() { - super(Outcome.PutCreatureInPlay); - staticText = "Create a 1/1 black and green Insect creature token, then mill two cards. " - + "Put a deathtouch counter on the token if a black card was milled this way."; - } - - private GristThePlagueSwarmPlus1Effect(final GristThePlagueSwarmPlus1Effect effect) { - super(effect); - } - - @Override - public GristThePlagueSwarmPlus1Effect copy() { - return new GristThePlagueSwarmPlus1Effect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - // Create a 1/1 black and green Insect creature token - CreateTokenEffect effect = new CreateTokenEffect(new IzoniInsectToken()); - effect.apply(game, source); - - // Then mill two cards - Cards cards = controller.millCards(2, source, game); - - // Put a deathtouch counter on the token if a black card was milled this way. - if (cards.getCards(game).stream().anyMatch(card -> card.getColor(game).isBlack())) { - List tokens = effect - .getLastAddedTokenIds() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - if (!tokens.isEmpty()) { - Effect addEffect = new AddCountersTargetEffect(CounterType.DEATHTOUCH.createInstance()); - addEffect.setTargetPointer(new FixedTargets(tokens, game)); - addEffect.apply(game, source); - } - } - return true; - } -} - -class GristThePlagueSwarmMinus6Effect extends OneShotEffect { - - GristThePlagueSwarmMinus6Effect() { - super(Outcome.PutCreatureInPlay); - staticText = "For each creature card in your graveyard, create a token that's a copy of it, " - + "except it's a 1/1 black and green Insect."; - } - - private GristThePlagueSwarmMinus6Effect(final GristThePlagueSwarmMinus6Effect effect) { - super(effect); - } - - @Override - public GristThePlagueSwarmMinus6Effect copy() { - return new GristThePlagueSwarmMinus6Effect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Set cards = controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game); - if (cards.isEmpty()) { - return false; - } - for (Card card : cards) { - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( - null, null, false, 1, false, - false, null, 1, 1, false - ); - effect.setSavedPermanent(new PermanentCard(card, controller.getId(), game)); - effect.setOnlyColor(new ObjectColor("BG")); - effect.setOnlySubType(SubType.INSECT); - effect.apply(game, source); - } - return true; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GristVoraciousLarva.java b/Mage.Sets/src/mage/cards/g/GristVoraciousLarva.java index e685b4684d1..0292cfb325f 100644 --- a/Mage.Sets/src/mage/cards/g/GristVoraciousLarva.java +++ b/Mage.Sets/src/mage/cards/g/GristVoraciousLarva.java @@ -1,46 +1,73 @@ package mage.cards.g; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; +import mage.game.permanent.token.IzoniInsectToken; import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTargets; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author Susucr */ -public final class GristVoraciousLarva extends CardImpl { +public final class GristVoraciousLarva extends TransformingDoubleFacedCard { public GristVoraciousLarva(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT}, "{G}", + "Grist, the Plague Swarm", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.GRIST}, "BG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.INSECT); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = GristThePlagueSwarm.class; + // Grist, Voracious Larva + this.getLeftHalfCard().setPT(1, 2); // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); + this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance()); // Whenever Grist, Voracious Larva or another creature you control enters, if it entered from your graveyard or was cast from your graveyard, you may pay {G}. If you do, exile Grist, then return it to the battlefield transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new GristVoraciousLarvaTriggeredAbility()); + this.getLeftHalfCard().addAbility(new GristVoraciousLarvaTriggeredAbility()); + + // Grist, the Plague Swarm + this.getRightHalfCard().setStartingLoyalty(3); + + // +1: Create a 1/1 black and green Insect creature token, then mill two cards. Put a deathtouch counter on the token if a black card was milled this way. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GristThePlagueSwarmPlus1Effect(), 1)); + + // -2: Destroy target artifact or enchantment. + Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -2); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.getRightHalfCard().addAbility(ability); + + // -6: For each creature card in your graveyard, create a token that's a copy of it, except it's a 1/1 black and green Insect. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GristThePlagueSwarmMinus6Effect(), -6)); } private GristVoraciousLarva(final GristVoraciousLarva card) { @@ -100,3 +127,93 @@ class GristVoraciousLarvaTriggeredAbility extends EntersBattlefieldThisOrAnother return fromGraveyard && super.checkTrigger(event, game); } } + +class GristThePlagueSwarmPlus1Effect extends OneShotEffect { + + GristThePlagueSwarmPlus1Effect() { + super(Outcome.PutCreatureInPlay); + staticText = "Create a 1/1 black and green Insect creature token, then mill two cards. " + + "Put a deathtouch counter on the token if a black card was milled this way."; + } + + private GristThePlagueSwarmPlus1Effect(final GristThePlagueSwarmPlus1Effect effect) { + super(effect); + } + + @Override + public GristThePlagueSwarmPlus1Effect copy() { + return new GristThePlagueSwarmPlus1Effect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + // Create a 1/1 black and green Insect creature token + CreateTokenEffect effect = new CreateTokenEffect(new IzoniInsectToken()); + effect.apply(game, source); + + // Then mill two cards + Cards cards = controller.millCards(2, source, game); + + // Put a deathtouch counter on the token if a black card was milled this way. + if (cards.getCards(game).stream().anyMatch(card -> card.getColor(game).isBlack())) { + List tokens = effect + .getLastAddedTokenIds() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (!tokens.isEmpty()) { + Effect addEffect = new AddCountersTargetEffect(CounterType.DEATHTOUCH.createInstance()); + addEffect.setTargetPointer(new FixedTargets(tokens, game)); + addEffect.apply(game, source); + } + } + return true; + } +} + +class GristThePlagueSwarmMinus6Effect extends OneShotEffect { + + GristThePlagueSwarmMinus6Effect() { + super(Outcome.PutCreatureInPlay); + staticText = "For each creature card in your graveyard, create a token that's a copy of it, " + + "except it's a 1/1 black and green Insect."; + } + + private GristThePlagueSwarmMinus6Effect(final GristThePlagueSwarmMinus6Effect effect) { + super(effect); + } + + @Override + public GristThePlagueSwarmMinus6Effect copy() { + return new GristThePlagueSwarmMinus6Effect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Set cards = controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game); + if (cards.isEmpty()) { + return false; + } + for (Card card : cards) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( + null, null, false, 1, false, + false, null, 1, 1, false + ); + effect.setSavedPermanent(new PermanentCard(card, controller.getId(), game)); + effect.setOnlyColor(new ObjectColor("BG")); + effect.setOnlySubType(SubType.INSECT); + effect.apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java index ac856108974..0753f9ef08e 100644 --- a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java +++ b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java @@ -1,20 +1,22 @@ package mage.cards.g; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ColorlessPredicate; @@ -23,7 +25,7 @@ import java.util.UUID; /** * @author fireshoes */ -public final class GrizzledAngler extends CardImpl { +public final class GrizzledAngler extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard(); @@ -34,21 +36,30 @@ public final class GrizzledAngler extends CardImpl { private static final Condition condition = new CardsInControllerGraveyardCondition(1, filter); public GrizzledAngler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{2}{U}", + "Grisly Anglerfish", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.FISH}, "" + ); - this.secondSideCardClazz = mage.cards.g.GrislyAnglerfish.class; + // Grizzled Angler + this.getLeftHalfCard().setPT(2, 3); // {T}: Put the top two cards of your library into your graveyard. Then if there is a colorless creature card in your graveyard, transform Grizzled Angler. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new MillCardsControllerEffect(2), new TapSourceCost()); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), condition, "Then if there is a colorless creature card in your graveyard, transform {this}" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Grisly Anglerfish + this.getRightHalfCard().setPT(4, 5); + + // {6}: Creatures your opponents control attack this turn if able. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new AttacksIfAbleAllEffect( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn + ), new ManaCostsImpl<>("{6}"))); } private GrizzledAngler(final GrizzledAngler card) { diff --git a/Mage.Sets/src/mage/cards/g/GrizzledOutcasts.java b/Mage.Sets/src/mage/cards/g/GrizzledOutcasts.java index ab0bcf6566e..3c8ba3067e0 100644 --- a/Mage.Sets/src/mage/cards/g/GrizzledOutcasts.java +++ b/Mage.Sets/src/mage/cards/g/GrizzledOutcasts.java @@ -1,33 +1,38 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import java.util.UUID; /** * @author nantuko */ -public final class GrizzledOutcasts extends CardImpl { +public final class GrizzledOutcasts extends TransformingDoubleFacedCard { public GrizzledOutcasts(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}", + "Krallenhorde Wantons", + new SuperType[]{}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.k.KrallenhordeWantons.class; - - this.power = new MageInt(4); - this.toughness = new MageInt(4); + // Grizzled Outcasts + this.getLeftHalfCard().setPT(4, 4); // At the beginning of each upkeep, if no spells were cast last turn, transform Grizzled Outcasts. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Krallenhorde Wantons + this.getRightHalfCard().setPT(7, 7); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Wantons. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private GrizzledOutcasts(final GrizzledOutcasts card) { diff --git a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java index cbc80fc495e..3969690b886 100644 --- a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java +++ b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java @@ -1,19 +1,19 @@ package mage.cards.g; +import mage.Mana; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.common.CreaturesYouControlHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.DynamicManaAbility; +import mage.abilities.mana.GreenManaAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.PutCards; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; @@ -22,7 +22,7 @@ import java.util.UUID; /** * @author JRHerlehy */ -public final class GrowingRitesOfItlimoc extends CardImpl { +public final class GrowingRitesOfItlimoc extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledCreaturePermanent("you control four or more creatures"), @@ -30,23 +30,30 @@ public final class GrowingRitesOfItlimoc extends CardImpl { ); public GrowingRitesOfItlimoc(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{G}", + "Itlimoc, Cradle of the Sun", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.i.ItlimocCradleOfTheSun.class; - - // 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( + // Growing Rites of Itlimoc + // 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.getLeftHalfCard().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()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(CreaturesYouControlHint.instance)); + + // Itlimoc, Cradle of the Sun + // {T}: Add {G}. + this.getRightHalfCard().addAbility(new GreenManaAbility()); + + // {T}: Add {G} for each creature you control. + this.getRightHalfCard().addAbility(new DynamicManaAbility( + Mana.GreenMana(1), CreaturesYouControlCount.SINGULAR + ).addHint(CreaturesYouControlHint.instance)); } private GrowingRitesOfItlimoc(final GrowingRitesOfItlimoc card) { diff --git a/Mage.Sets/src/mage/cards/g/GuidestoneCompass.java b/Mage.Sets/src/mage/cards/g/GuidestoneCompass.java deleted file mode 100644 index 7b7d39633ca..00000000000 --- a/Mage.Sets/src/mage/cards/g/GuidestoneCompass.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.keyword.ExploreTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.target.common.TargetControlledCreaturePermanent; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class GuidestoneCompass extends CardImpl { - - public GuidestoneCompass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.nightCard = true; - this.color.setBlue(true); - - // {1}, {T}: Target creature you control explores. Activate only as a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility( - new ExploreTargetEffect(), - new GenericManaCost(1) - ); - ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private GuidestoneCompass(final GuidestoneCompass card) { - super(card); - } - - @Override - public GuidestoneCompass copy() { - return new GuidestoneCompass(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GuildpactParagon.java b/Mage.Sets/src/mage/cards/g/GuildpactParagon.java deleted file mode 100644 index c0dd3510078..00000000000 --- a/Mage.Sets/src/mage/cards/g/GuildpactParagon.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.g; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.FilterSpell; -import mage.filter.predicate.Predicate; -import mage.game.Game; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class GuildpactParagon extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("a spell that's exactly two colors"); - private static final FilterCard filter2 = new FilterCard("a card that's exactly two colors"); - - static { - filter.add(GuildpactParagonPredicate.instance); - filter2.add(GuildpactParagonPredicate.instance); - } - - public GuildpactParagon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - - // Whenever you cast a spell that's exactly two colors, look at the top six cards of your library. You may reveal a card that's exactly two colors 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 SpellCastControllerTriggeredAbility(new LookLibraryAndPickControllerEffect( - 6, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM - ), filter, false)); - } - - private GuildpactParagon(final GuildpactParagon card) { - super(card); - } - - @Override - public GuildpactParagon copy() { - return new GuildpactParagon(this); - } -} - -enum GuildpactParagonPredicate implements Predicate { - instance; - - @Override - public boolean apply(MageObject input, Game game) { - return input.getColor(game).getColorCount() == 2; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GuruPathik.java b/Mage.Sets/src/mage/cards/g/GuruPathik.java new file mode 100644 index 00000000000..2e4271ec413 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuruPathik.java @@ -0,0 +1,76 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuruPathik extends CardImpl { + + private static final FilterCard filter = new FilterCard("a Lesson, Saga, or Shrine card"); + private static final FilterSpell filter2 = new FilterSpell("a Lesson, Saga, or Shrine spell"); + + static { + filter.add(Predicates.or( + SubType.LESSON.getPredicate(), + SubType.SAGA.getPredicate(), + SubType.SHRINE.getPredicate() + )); + filter2.add(Predicates.or( + SubType.LESSON.getPredicate(), + SubType.SAGA.getPredicate(), + SubType.SHRINE.getPredicate() + )); + } + + public GuruPathik(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G/U}{G/U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // When Guru Pathik enters, look at the top five cards of your library. You may reveal a Lesson, Saga, or Shrine 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( + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ))); + + // Whenever you cast a Lesson, Saga, or Shrine spell, put a +1/+1 counter on another target creature you control. + Ability ability = new SpellCastControllerTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), filter2, false + ); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private GuruPathik(final GuruPathik card) { + super(card); + } + + @Override + public GuruPathik copy() { + return new GuruPathik(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GutterShortcut.java b/Mage.Sets/src/mage/cards/g/GutterShortcut.java deleted file mode 100644 index bfb716b5d02..00000000000 --- a/Mage.Sets/src/mage/cards/g/GutterShortcut.java +++ /dev/null @@ -1,71 +0,0 @@ -package mage.cards.g; - -import mage.abilities.Ability; -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.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -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.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 GutterShortcut extends CardImpl { - - public GutterShortcut(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature can't be blocked as long as it's attacking alone. - this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( - new CantBeBlockedAttachedEffect(AttachmentType.AURA), GutterShortcutCondition.instance, - "enchanted creature can't be blocked as long as it's attacking alone" - ))); - - // If Gutter Shortcut would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private GutterShortcut(final GutterShortcut card) { - super(card); - } - - @Override - public GutterShortcut copy() { - return new GutterShortcut(this); - } -} - -enum GutterShortcutCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - return permanent != null && game.getCombat().attacksAlone() - && game.getCombat().getAttackers().contains(permanent.getAttachedTo()); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GutterSkulker.java b/Mage.Sets/src/mage/cards/g/GutterSkulker.java index 674a82f29b8..ec68e6828b0 100644 --- a/Mage.Sets/src/mage/cards/g/GutterSkulker.java +++ b/Mage.Sets/src/mage/cards/g/GutterSkulker.java @@ -1,42 +1,68 @@ package mage.cards.g; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceAttackingAloneCondition; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.UUID; /** * @author TheElk801 */ -public final class GutterSkulker extends CardImpl { +public final class GutterSkulker extends TransformingDoubleFacedCard { public GutterSkulker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{3}{U}", + "Gutter Shortcut", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U" + ); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.g.GutterShortcut.class; + // Gutter Skulker + this.getLeftHalfCard().setPT(3, 3); // Gutter Skulker can't be blocked as long as it's attacking alone. - this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( new CantBeBlockedSourceEffect(Duration.WhileOnBattlefield), SourceAttackingAloneCondition.instance, "{this} can't be blocked as long as it's attacking alone" ))); + // Gutter Shortcut + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {3}{U} - this.addAbility(new DisturbAbility(this, "{3}{U}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{U}")); + + // Enchanted creature can't be blocked as long as it's attacking alone. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedSourceEffect(), GutterShortcutCondition.instance, + "enchanted creature can't be blocked as long as it's attacking alone" + ))); + + // If Gutter Shortcut would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private GutterSkulker(final GutterSkulker card) { @@ -48,3 +74,14 @@ public final class GutterSkulker extends CardImpl { return new GutterSkulker(this); } } + +enum GutterShortcutCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return permanent != null && game.getCombat().attacksAlone() + && game.getCombat().getAttackers().contains(permanent.getAttachedTo()); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java b/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java index dc637d370e3..a6b24fab20e 100644 --- a/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java +++ b/Mage.Sets/src/mage/cards/g/GwenomRemorseless.java @@ -46,7 +46,7 @@ public final class GwenomRemorseless extends CardImpl { // Whenever Gwenom attacks, until end of turn you may look at the top card of your library any time and you may play cards from the top of your library. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost. ContinuousEffect libraryAnyTimeEffect = new LookAtTopCardOfLibraryAnyTimeEffect(Duration.EndOfTurn); - libraryAnyTimeEffect.setText("until end of turn you may look at the top card of your library any time"); + libraryAnyTimeEffect.setText("until end of turn, you may look at the top card of your library any time"); libraryAnyTimeEffect.concatBy(" "); AsThoughEffectImpl playCardEffect = new GwenomRemorselessPlayTopCardEffect(); playCardEffect.concatBy("and"); diff --git a/Mage.Sets/src/mage/cards/h/HadanasClimb.java b/Mage.Sets/src/mage/cards/h/HadanasClimb.java index a1d27468050..319731b1df4 100644 --- a/Mage.Sets/src/mage/cards/h/HadanasClimb.java +++ b/Mage.Sets/src/mage/cards/h/HadanasClimb.java @@ -1,41 +1,60 @@ - package mage.cards.h; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.TargetHasCounterCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** * @author LevelX2 */ -public final class HadanasClimb extends CardImpl { +public final class HadanasClimb extends TransformingDoubleFacedCard { public HadanasClimb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{U}"); - - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.w.WingedTempleOfOrazca.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{G}{U}", + "Winged Temple of Orazca", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Hadana's Climb // At the beginning of combat on your turn, put a +1/+1 counter on target creature you control. Then if that creature has three or more +1/+1 counters on it, transform Hadana's Climb. - this.addAbility(new TransformAbility()); Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addEffect(new ConditionalOneShotEffect(new TransformSourceEffect(), new TargetHasCounterCondition(CounterType.P1P1, 3, Integer.MAX_VALUE), "Then if that creature has three or more +1/+1 counters on it, transform {this}")); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Winged Temple of Orazca + // {T}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); + + // {1}{G}{U}, {T}: Target creature you control gains flying and gets +X/+X until end of turn, where X is its power. + Ability backAbility = new SimpleActivatedAbility(new WingedTempleOfOrazcaEffect(), new ManaCostsImpl<>("{1}{G}{U}")); + backAbility.addCost(new TapSourceCost()); + backAbility.addTarget(new TargetControlledCreaturePermanent()); + this.getRightHalfCard().addAbility(backAbility); } private HadanasClimb(final HadanasClimb card) { @@ -47,3 +66,35 @@ public final class HadanasClimb extends CardImpl { return new HadanasClimb(this); } } + +class WingedTempleOfOrazcaEffect extends OneShotEffect { + + WingedTempleOfOrazcaEffect() { + super(Outcome.Benefit); + this.staticText = "target creature you control gains flying and gets +X/+X until end of turn, where X is its power"; + } + + private WingedTempleOfOrazcaEffect(final WingedTempleOfOrazcaEffect effect) { + super(effect); + } + + @Override + public WingedTempleOfOrazcaEffect copy() { + return new WingedTempleOfOrazcaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature != null && creature.isCreature(game)) { + int pow = creature.getPower().getValue(); + ContinuousEffect effect = new BoostTargetEffect(pow, pow, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature, game)); + game.addEffect(effect, source); + effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature, game)); + game.addEffect(effect, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java b/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java deleted file mode 100644 index 270bb430e07..00000000000 --- a/Mage.Sets/src/mage/cards/h/HadesSorcererOfEld.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.decorator.ConditionalAsThoughEffect; -import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; -import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; - -import java.util.UUID; - -/** - * @author balazskristof - */ -public final class HadesSorcererOfEld extends CardImpl { - - public HadesSorcererOfEld(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Echo of the Lost -- During your turn you may play cards from your graveyard. - this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( - PlayFromGraveyardControllerEffect.playCards(), MyTurnCondition.instance - ).setText("during your turn, you may play cards from your graveyard")).withFlavorWord("Echo of the Lost")); - - // If a card or token would be put into your graveyard from anywhere, exile it instead. - this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true))); - } - - private HadesSorcererOfEld(final HadesSorcererOfEld card) { - super(card); - } - - @Override - public HadesSorcererOfEld copy() { - return new HadesSorcererOfEld(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HailStorm.java b/Mage.Sets/src/mage/cards/h/HailStorm.java index 8668f420724..71c0938b515 100644 --- a/Mage.Sets/src/mage/cards/h/HailStorm.java +++ b/Mage.Sets/src/mage/cards/h/HailStorm.java @@ -1,14 +1,18 @@ - package mage.cards.h; -import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; +import mage.game.Game; + +import java.util.UUID; /** * @@ -20,9 +24,7 @@ public final class HailStorm extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}{G}"); // Hail Storm deals 2 damage to each attacking creature and 1 damage to you and each creature you control. - this.getSpellAbility().addEffect(new DamageAllEffect(2, new FilterAttackingCreature())); - this.getSpellAbility().addEffect(new DamageControllerEffect(1).setText("and 1 damage to you")); - this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED).setText("and each creature you control.")); + this.getSpellAbility().addEffect(new HailStormEffect()); } private HailStorm(final HailStorm card) { @@ -34,3 +36,32 @@ public final class HailStorm extends CardImpl { return new HailStorm(this); } } + +// needed for simultaneous damage +class HailStormEffect extends OneShotEffect { + + private static final FilterAttackingCreature filter = new FilterAttackingCreature(); + + HailStormEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 2 damage to each attacking creature " + + "and 1 damage to you and each creature you control"; + } + + private HailStormEffect(final HailStormEffect effect) { + super(effect); + } + + @Override + public HailStormEffect copy() { + return new HailStormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new DamageAllEffect(2, filter).apply(game, source); + new DamageControllerEffect(1).apply(game, source); + new DamageAllEffect(1, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED).apply(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java b/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java new file mode 100644 index 00000000000..034e8a07f6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HamaTheBloodbender.java @@ -0,0 +1,152 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.cards.Card; +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.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HamaTheBloodbender extends CardImpl { + + public HamaTheBloodbender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/B}{U/B}{U/B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Hama enters, target opponent mills three cards. Exile up to one noncreature, nonland card from that player's graveyard. For as long as you control Hama, you may cast the exiled card during your turn by waterbending {X} rather than paying its mana cost, where X is its mana value. + Ability ability = new EntersBattlefieldTriggeredAbility(new MillCardsTargetEffect(3)); + ability.addEffect(new HamaTheBloodbenderExileEffect()); + this.addAbility(ability); + } + + private HamaTheBloodbender(final HamaTheBloodbender card) { + super(card); + } + + @Override + public HamaTheBloodbender copy() { + return new HamaTheBloodbender(this); + } +} + +class HamaTheBloodbenderExileEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("noncreature, nonland card"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + HamaTheBloodbenderExileEffect() { + super(Outcome.Benefit); + staticText = "Exile up to one noncreature, nonland card from that player's graveyard. " + + "For as long as you control {this}, you may cast the exiled card during your turn " + + "by waterbending {X} rather than paying its mana cost, where X is its mana value."; + } + + private HamaTheBloodbenderExileEffect(final HamaTheBloodbenderExileEffect effect) { + super(effect); + } + + @Override + public HamaTheBloodbenderExileEffect copy() { + return new HamaTheBloodbenderExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { + return false; + } + TargetCard target = new TargetCardInGraveyard(0, 1, filter, true); + controller.choose(Outcome.PlayForFree, opponent.getGraveyard(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + controller.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + if (source.getSourcePermanentIfItStillExists(game) != null) { + game.addEffect(new HamaTheBloodbenderCastEffect(card, game), source); + } + return true; + } +} + +class HamaTheBloodbenderCastEffect extends AsThoughEffectImpl { + + HamaTheBloodbenderCastEffect(Card card, Game game) { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileControlled, Outcome.AIDontUseIt); + this.setTargetPointer(new FixedTarget(card, game)); + } + + private HamaTheBloodbenderCastEffect(final HamaTheBloodbenderCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public HamaTheBloodbenderCastEffect copy() { + return new HamaTheBloodbenderCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!game.isActivePlayer(affectedControllerId) || !source.isControlledBy(affectedControllerId)) { + return false; + } + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + discard(); + return false; + } + if (!card.getId().equals(objectId)) { + return false; + } + Player player = game.getPlayer(affectedControllerId); + if (player == null) { + return false; + } + Costs newCosts = new CostsImpl<>(); + newCosts.add(new WaterbendCost(card.getManaValue())); + newCosts.addAll(card.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(card.getId(), null, newCosts); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java b/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java deleted file mode 100644 index bd13b8a3582..00000000000 --- a/Mage.Sets/src/mage/cards/h/HandOfEnlightenment.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.keyword.FirstStrikeAbility; -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 HandOfEnlightenment extends CardImpl { - - public HandOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MONK); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setWhite(true); - this.nightCard = true; - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - } - - private HandOfEnlightenment(final HandOfEnlightenment card) { - super(card); - } - - @Override - public HandOfEnlightenment copy() { - return new HandOfEnlightenment(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java b/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java index a6bb769ba9c..39db9ab604e 100644 --- a/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java +++ b/Mage.Sets/src/mage/cards/h/HanweirMilitiaCaptain.java @@ -1,25 +1,30 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.hint.common.CreaturesYouControlHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.permanent.token.HumanClericToken; import java.util.UUID; /** * @author fireshoes */ -public final class HanweirMilitiaCaptain extends CardImpl { +public final class HanweirMilitiaCaptain extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledCreaturePermanent("you control four or more creatures"), @@ -27,18 +32,27 @@ public final class HanweirMilitiaCaptain extends CardImpl { ); public HanweirMilitiaCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{1}{W}", + "Westvale Cult Leader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "W" + ); - this.secondSideCardClazz = mage.cards.w.WestvaleCultLeader.class; + // Hanweir Militia Captain + this.getLeftHalfCard().setPT(2, 2); // At the beginning of your upkeep, if you control four or more creatures, transform Hanweir Militia Captain. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(CreaturesYouControlHint.instance)); + + // Westvale Cult Leader + // Westvale Cult Leader's power and toughness are each equal to the number of creatures you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, + new SetBasePowerToughnessSourceEffect(CreaturesYouControlCount.PLURAL)) + .addHint(CreaturesYouControlHint.instance)); + + // At the beginning of your end step, create a 1/1 white and black Human Cleric creature token. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new HumanClericToken()))); } private HanweirMilitiaCaptain(final HanweirMilitiaCaptain card) { diff --git a/Mage.Sets/src/mage/cards/h/HanweirWatchkeep.java b/Mage.Sets/src/mage/cards/h/HanweirWatchkeep.java index 85997f17d36..3919e5c1f4e 100644 --- a/Mage.Sets/src/mage/cards/h/HanweirWatchkeep.java +++ b/Mage.Sets/src/mage/cards/h/HanweirWatchkeep.java @@ -1,11 +1,11 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.common.AttacksEachCombatStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,23 +14,32 @@ import java.util.UUID; /** * @author nantuko */ -public final class HanweirWatchkeep extends CardImpl { +public final class HanweirWatchkeep extends TransformingDoubleFacedCard { public HanweirWatchkeep(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{2}{R}", + "Bane of Hanweir", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.b.BaneOfHanweir.class; + // Hanweir Watchkeep + this.getLeftHalfCard().setPT(1, 5); - this.power = new MageInt(1); - this.toughness = new MageInt(5); + // Defender + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); - this.addAbility(DefenderAbility.getInstance()); // At the beginning of each upkeep, if no spells were cast last turn, transform Hanweir Watchkeep. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Bane of Hanweir + this.getRightHalfCard().setPT(5, 5); + + // Bane of Hanweir attacks each turn if able. + this.getRightHalfCard().addAbility(new AttacksEachCombatStaticAbility()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Bane of Hanweir. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private HanweirWatchkeep(final HanweirWatchkeep card) { diff --git a/Mage.Sets/src/mage/cards/h/HarriedArtisan.java b/Mage.Sets/src/mage/cards/h/HarriedArtisan.java index f9ca5ca64a8..24126b3e162 100644 --- a/Mage.Sets/src/mage/cards/h/HarriedArtisan.java +++ b/Mage.Sets/src/mage/cards/h/HarriedArtisan.java @@ -1,13 +1,12 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -16,23 +15,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HarriedArtisan extends CardImpl { +public final class HarriedArtisan extends TransformingDoubleFacedCard { public HarriedArtisan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ARTIFICER}, "{2}{R}", + "Phyrexian Skyflayer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ARTIFICER}, "WR" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ARTIFICER); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.p.PhyrexianSkyflayer.class; + // Harried Artisan + this.getLeftHalfCard().setPT(2, 3); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // {3}{W/P}: Transform Harried Artisan. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{W/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{W/P}"))); + + // Phyrexian Skyflayer + this.getRightHalfCard().setPT(3, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); } private HarriedArtisan(final HarriedArtisan card) { diff --git a/Mage.Sets/src/mage/cards/h/HarshMentor.java b/Mage.Sets/src/mage/cards/h/HarshMentor.java index d317abe73b2..1c5332d40e4 100644 --- a/Mage.Sets/src/mage/cards/h/HarshMentor.java +++ b/Mage.Sets/src/mage/cards/h/HarshMentor.java @@ -2,7 +2,6 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.Card; @@ -48,7 +47,8 @@ public final class HarshMentor extends CardImpl { class HarshMentorTriggeredAbility extends TriggeredAbilityImpl { HarshMentorTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(2), true, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, "); } private HarshMentorTriggeredAbility(final HarshMentorTriggeredAbility ability) { @@ -82,8 +82,4 @@ class HarshMentorTriggeredAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, {this} deals 2 damage to that player."; - } } diff --git a/Mage.Sets/src/mage/cards/h/HarvestHand.java b/Mage.Sets/src/mage/cards/h/HarvestHand.java index 4b55e43df98..ad517955f58 100644 --- a/Mage.Sets/src/mage/cards/h/HarvestHand.java +++ b/Mage.Sets/src/mage/cards/h/HarvestHand.java @@ -1,18 +1,21 @@ package mage.cards.h; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.EquippedHasSubtypeCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.TransformAbility; 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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.game.Game; import mage.players.Player; @@ -21,19 +24,36 @@ import java.util.UUID; /** * @author halljared */ -public final class HarvestHand extends CardImpl { +public final class HarvestHand extends TransformingDoubleFacedCard { + + private static final Condition condition = new EquippedHasSubtypeCondition(SubType.HUMAN); public HarvestHand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); - this.subtype.add(SubType.SCARECROW); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.SCARECROW}, "{3}", + "Scrounged Scythe", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "" + ); - this.secondSideCardClazz = mage.cards.s.ScroungedScythe.class; + // Harvest Hand + this.getLeftHalfCard().setPT(2, 2); // When Harvest Hand dies, return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new HarvestHandReturnTransformedEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new HarvestHandReturnTransformedEffect())); + + // Scrounged Scythe + // Equipped creature gets +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + + // As long as equipped creature is a Human, it has menace. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(new MenaceAbility(false), AttachmentType.EQUIPMENT), + condition, "As long as equipped creature is a Human, it has menace. " + + "(It can't be blocked except by two or more creatures.)" + ))); + + // Equip {2} + this.getRightHalfCard().addAbility(new EquipAbility(2, false)); } private HarvestHand(final HarvestHand card) { diff --git a/Mage.Sets/src/mage/cards/h/HarvesttideAssailant.java b/Mage.Sets/src/mage/cards/h/HarvesttideAssailant.java deleted file mode 100644 index c1d10320d80..00000000000 --- a/Mage.Sets/src/mage/cards/h/HarvesttideAssailant.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -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 HarvesttideAssailant extends CardImpl { - - public HarvesttideAssailant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private HarvesttideAssailant(final HarvesttideAssailant card) { - super(card); - } - - @Override - public HarvesttideAssailant copy() { - return new HarvesttideAssailant(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HarvesttideInfiltrator.java b/Mage.Sets/src/mage/cards/h/HarvesttideInfiltrator.java index f6258d61b69..3777b180973 100644 --- a/Mage.Sets/src/mage/cards/h/HarvesttideInfiltrator.java +++ b/Mage.Sets/src/mage/cards/h/HarvesttideInfiltrator.java @@ -1,10 +1,10 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +13,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HarvesttideInfiltrator extends CardImpl { +public final class HarvesttideInfiltrator extends TransformingDoubleFacedCard { public HarvesttideInfiltrator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}", + "Harvesttide Assailant", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.h.HarvesttideAssailant.class; + // Harvesttide Infiltrator + this.getLeftHalfCard().setPT(3, 2); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Harvesttide Assailant + this.getRightHalfCard().setPT(4, 4); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private HarvesttideInfiltrator(final HarvesttideInfiltrator card) { diff --git a/Mage.Sets/src/mage/cards/h/HaukensInsight.java b/Mage.Sets/src/mage/cards/h/HaukensInsight.java deleted file mode 100644 index d2b944a5f9e..00000000000 --- a/Mage.Sets/src/mage/cards/h/HaukensInsight.java +++ /dev/null @@ -1,202 +0,0 @@ -package mage.cards.h; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import mage.MageIdentifier; -import mage.MageObject; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.constants.*; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; -import mage.watchers.Watcher; - -/** - * - * @author weirddan455 - */ -public final class HaukensInsight extends CardImpl { - - public HaukensInsight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.color.setBlue(true); - // Back half of Jacob Hauken, Inspector - this.nightCard = true; - - // At the beginning of your upkeep, exile the top card of your library face down. You may look at that card for as long as it remains exiled. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new HaukensInsightExileEffect())); - - // Once during each of your turns, you may play a land or cast a spell from among the cards exiled with this permanent without paying its mana cost. - this.addAbility(new SimpleStaticAbility(new HaukensInsightPlayEffect()) - .setIdentifier(MageIdentifier.HaukensInsightWatcher), - new HaukensInsightWatcher()); - } - - private HaukensInsight(final HaukensInsight card) { - super(card); - } - - @Override - public HaukensInsight copy() { - return new HaukensInsight(this); - } -} - -class HaukensInsightExileEffect extends OneShotEffect { - - HaukensInsightExileEffect() { - super(Outcome.Benefit); - staticText = "exile the top card of your library face down. You may look at that card for as long as it remains exiled"; - } - - private HaukensInsightExileEffect(final HaukensInsightExileEffect effect) { - super(effect); - } - - @Override - public HaukensInsightExileEffect copy() { - return new HaukensInsightExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC()); - MageObject sourceObject = source.getSourceObject(game); - String exileName = sourceObject == null ? null : sourceObject.getIdName(); - card.setFaceDown(true, game); - controller.moveCardsToExile(card, source, game, false, exileId, exileName); - if (game.getState().getZone(card.getId()) == Zone.EXILED) { - card.setFaceDown(true, game); - HaukensInsightLookEffect effect = new HaukensInsightLookEffect(controller.getId()); - effect.setTargetPointer(new FixedTarget(card, game)); - game.addEffect(effect, source); - return true; - } - } - } - return false; - } -} - -class HaukensInsightLookEffect extends AsThoughEffectImpl { - - private final UUID authorizedPlayerId; - - public HaukensInsightLookEffect(UUID authorizedPlayerId) { - super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); - this.authorizedPlayerId = authorizedPlayerId; - } - - private HaukensInsightLookEffect(final HaukensInsightLookEffect effect) { - super(effect); - this.authorizedPlayerId = effect.authorizedPlayerId; - } - - @Override - public HaukensInsightLookEffect copy() { - return new HaukensInsightLookEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - UUID cardId = getTargetPointer().getFirst(game, source); - if (cardId == null) { - this.discard(); // card is no longer in the origin zone, effect can be discarded - } - return affectedControllerId.equals(authorizedPlayerId) - && objectId.equals(cardId); - } -} - -class HaukensInsightPlayEffect extends AsThoughEffectImpl { - - HaukensInsightPlayEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PlayForFree); - staticText = "Once during each of your turns, you may play a land or cast a spell from among the cards exiled with this permanent without paying its mana cost"; - } - - private HaukensInsightPlayEffect(final HaukensInsightPlayEffect effect) { - super(effect); - } - - @Override - public HaukensInsightPlayEffect copy() { - return new HaukensInsightPlayEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && game.isActivePlayer(source.getControllerId())) { - Player controller = game.getPlayer(source.getControllerId()); - HaukensInsightWatcher watcher = game.getState().getWatcher(HaukensInsightWatcher.class); - Permanent sourceObject = game.getPermanent(source.getSourceId()); - if (controller != null && watcher != null && sourceObject != null && !watcher.isAbilityUsed(new MageObjectReference(sourceObject, game))) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())); - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone != null && exileZone.contains(CardUtil.getMainCardId(game, objectId))) { - allowCardToPlayWithoutMana(objectId, source, affectedControllerId, MageIdentifier.HaukensInsightWatcher, game); - return true; - } - } - } - return false; - } -} - -class HaukensInsightWatcher extends Watcher { - - private final Set usedFrom = new HashSet<>(); - - public HaukensInsightWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST || event.getType() == GameEvent.EventType.LAND_PLAYED) { - if (event.hasApprovingIdentifier(MageIdentifier.HaukensInsightWatcher)) { - usedFrom.add(event.getApprovingObject().getApprovingMageObjectReference()); - } - } - } - - @Override - public void reset() { - super.reset(); - usedFrom.clear(); - } - - public boolean isAbilityUsed(MageObjectReference mor) { - return usedFrom.contains(mor); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java b/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java index f587b2cfd43..0d8337fffdd 100644 --- a/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java +++ b/Mage.Sets/src/mage/cards/h/HauntOfTheDeadMarshes.java @@ -1,23 +1,17 @@ package mage.cards.h; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.effects.keyword.ScryEffect; -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.SubType; -import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import java.util.UUID; @@ -26,16 +20,6 @@ import java.util.UUID; */ public final class HauntOfTheDeadMarshes extends CardImpl { - private static final FilterPermanent filter - = new FilterControlledCreaturePermanent("you control a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); - private static final Hint hint = new ConditionHint(condition, "You control a legendary creature"); - public HauntOfTheDeadMarshes(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); @@ -50,8 +34,8 @@ public final class HauntOfTheDeadMarshes extends CardImpl { // {2}{B}: Return Haunt of the Dead Marshes from your graveyard to the battlefield tapped. Activate only if you control a legendary creature. this.addAbility(new ActivateIfConditionActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), - new ManaCostsImpl<>("{2}{B}"), condition - ).addHint(hint)); + new ManaCostsImpl<>("{2}{B}"), YouControlALegendaryCreatureCondition.instance + ).addHint(YouControlALegendaryCreatureCondition.getHint())); } private HauntOfTheDeadMarshes(final HauntOfTheDeadMarshes card) { diff --git a/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java b/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java index 766da704cd2..b95a4204275 100644 --- a/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java +++ b/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java @@ -1,53 +1,79 @@ package mage.cards.h; +import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.keyword.InvestigateEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +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.players.Player; +import mage.target.common.TargetCardInYourGraveyard; import mage.util.CardUtil; import mage.watchers.Watcher; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; /** * @author TheElk801 */ -public final class HavengulLaboratory extends CardImpl { +public final class HavengulLaboratory extends TransformingDoubleFacedCard { public HavengulLaboratory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.h.HavengulMystery.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "", + "Havengul Mystery", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Havengul Laboratory // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); + this.getLeftHalfCard().addAbility(new ColorlessManaAbility()); // {4}, {T}: Investigate. Ability ability = new SimpleActivatedAbility(new InvestigateEffect(), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your end step, if you sacrificed three or more Clues this turn, transform Havengul Laboratory. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( + Ability transformAbility = new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new TransformSourceEffect(), false, HavengulLaboratoryCondition.instance - ), new HavengulLaboratoryWatcher()); + ); + transformAbility.addWatcher(new HavengulLaboratoryWatcher()); + this.getLeftHalfCard().addAbility(transformAbility); + + // Havengul Mystery + // When this land transforms into Havengul Mystery, return target creature card from your graveyard to the battlefield. + Ability backAbility = new TransformIntoSourceTriggeredAbility(new HavengulMysteryEffect()) + .setTriggerPhrase("When this land transforms into {this}, "); + backAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(backAbility); + + // When the creature put onto the battlefield with Havengul Mystery leaves the battlefield, transform Havengul Mystery. + this.getRightHalfCard().addAbility(new HavengulMysteryLeavesAbility()); + + // {T}, Pay 1 life: Add {B}. + Ability manaAbility = new BlackManaAbility(); + manaAbility.addCost(new PayLifeCost(1)); + this.getRightHalfCard().addAbility(manaAbility); } private HavengulLaboratory(final HavengulLaboratory card) { @@ -108,3 +134,89 @@ class HavengulLaboratoryWatcher extends Watcher { .getOrDefault(playerId, 0) >= 3; } } + +class HavengulMysteryEffect extends OneShotEffect { + + HavengulMysteryEffect() { + super(Outcome.Benefit); + staticText = "return target creature card from your graveyard to the battlefield"; + } + + private HavengulMysteryEffect(final HavengulMysteryEffect effect) { + super(effect); + } + + @Override + public HavengulMysteryEffect copy() { + return new HavengulMysteryEffect(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 = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent == null) { + return false; + } + String key = HavengulMysteryLeavesAbility.makeKey(source, game); + Set morSet; + if (game.getState().getValue(key) != null) { + morSet = (Set) game.getState().getValue(key); + } else { + morSet = new HashSet<>(); + game.getState().setValue(key, morSet); + } + morSet.add(new MageObjectReference(permanent, game)); + return true; + } +} + +class HavengulMysteryLeavesAbility extends TriggeredAbilityImpl { + + HavengulMysteryLeavesAbility() { + super(Zone.BATTLEFIELD, new TransformSourceEffect()); + setLeavesTheBattlefieldTrigger(true); + } + + private HavengulMysteryLeavesAbility(final HavengulMysteryLeavesAbility ability) { + super(ability); + } + + @Override + public HavengulMysteryLeavesAbility copy() { + return new HavengulMysteryLeavesAbility(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; + if (zEvent.getFromZone() != Zone.BATTLEFIELD) { + return false; + } + + String key = makeKey(this, game); + Set morSet = (Set) game.getState().getValue(key); + return morSet != null + && !morSet.isEmpty() + && morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game)); + } + + @Override + public String getRule() { + return "When the creature put onto the battlefield with {this} leaves the battlefield, transform {this}."; + } + + static String makeKey(Ability source, Game game) { + return "HavengulMystery_" + source.getSourceId() + '_' + CardUtil.getActualSourceObjectZoneChangeCounter(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HavengulMystery.java b/Mage.Sets/src/mage/cards/h/HavengulMystery.java deleted file mode 100644 index 24cca60c3b1..00000000000 --- a/Mage.Sets/src/mage/cards/h/HavengulMystery.java +++ /dev/null @@ -1,150 +0,0 @@ -package mage.cards.h; - -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.mana.BlackManaAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; -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.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInYourGraveyard; -import mage.util.CardUtil; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HavengulMystery extends CardImpl { - - public HavengulMystery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // When this land transforms into Havengul Mystery, return target creature card from your graveyard to the battlefield. - Ability ability = new TransformIntoSourceTriggeredAbility(new HavengulMysteryEffect()) - .setTriggerPhrase("When this land transforms into {this}, "); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.addAbility(ability); - - // When the creature put onto the battlefield with Havengul Mystery leaves the battlefield, transform Havengul Mystery. - this.addAbility(new HavengulMysteryLeavesAbility()); - - // {T}, Pay 1 life: Add {B}. - Ability ability2 = new BlackManaAbility(); - ability2.addCost(new PayLifeCost(1)); - this.addAbility(ability2); - } - - private HavengulMystery(final HavengulMystery card) { - super(card); - } - - @Override - public HavengulMystery copy() { - return new HavengulMystery(this); - } - - static String makeKey(Ability source, Game game) { - return "HavengulMystery_" + source.getSourceId() + '_' + CardUtil.getActualSourceObjectZoneChangeCounter(game, source); - } -} - -class HavengulMysteryEffect extends OneShotEffect { - - HavengulMysteryEffect() { - super(Outcome.Benefit); - staticText = "return target creature card from your graveyard to the battlefield"; - } - - private HavengulMysteryEffect(final HavengulMysteryEffect effect) { - super(effect); - } - - @Override - public HavengulMysteryEffect copy() { - return new HavengulMysteryEffect(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 = CardUtil.getPermanentFromCardPutToBattlefield(card, game); - if (permanent == null) { - return false; - } - String key = HavengulMystery.makeKey(source, game); - Set morSet; - if (game.getState().getValue(key) != null) { - morSet = (Set) game.getState().getValue(key); - } else { - morSet = new HashSet<>(); - game.getState().setValue(key, morSet); - } - morSet.add(new MageObjectReference(permanent, game)); - return true; - } -} - -class HavengulMysteryLeavesAbility extends TriggeredAbilityImpl { - - HavengulMysteryLeavesAbility() { - super(Zone.BATTLEFIELD, new TransformSourceEffect()); - setLeavesTheBattlefieldTrigger(true); - } - - private HavengulMysteryLeavesAbility(final HavengulMysteryLeavesAbility ability) { - super(ability); - } - - @Override - public HavengulMysteryLeavesAbility copy() { - return new HavengulMysteryLeavesAbility(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; - if (zEvent.getFromZone() != Zone.BATTLEFIELD) { - return false; - } - - String key = HavengulMystery.makeKey(this, game); - Set morSet = (Set) game.getState().getValue(key); - return morSet != null - && !morSet.isEmpty() - && morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game)); - } - - @Override - public String getRule() { - return "When the creature put onto the battlefield with {this} leaves the battlefield, transform {this}."; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HealingGrace.java b/Mage.Sets/src/mage/cards/h/HealingGrace.java index 7a98ba94c80..2910fe321e1 100644 --- a/Mage.Sets/src/mage/cards/h/HealingGrace.java +++ b/Mage.Sets/src/mage/cards/h/HealingGrace.java @@ -1,7 +1,6 @@ package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.GainLifeEffect; @@ -15,6 +14,8 @@ import mage.game.events.GameEvent; import mage.target.TargetSource; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author TheElk801 @@ -70,12 +71,6 @@ class HealingGraceEffect extends PreventionEffectImpl { } } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - preventDamageAction(event, source, game); - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game)) { diff --git a/Mage.Sets/src/mage/cards/h/HeartOfLight.java b/Mage.Sets/src/mage/cards/h/HeartOfLight.java index a8ec748ad66..b38b66b42ed 100644 --- a/Mage.Sets/src/mage/cards/h/HeartOfLight.java +++ b/Mage.Sets/src/mage/cards/h/HeartOfLight.java @@ -7,12 +7,13 @@ import mage.abilities.effects.common.AttachEffect; import mage.abilities.keyword.EnchantAbility; 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.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -66,17 +67,6 @@ class HeartOfLightEffect extends PreventionEffectImpl { return new HeartOfLightEffect(this); } - @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 damage = event.getAmount(); - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game) && event instanceof DamageEvent) { diff --git a/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java b/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java new file mode 100644 index 00000000000..ab99c0180bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeiBaiForestGuardian.java @@ -0,0 +1,115 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledEnchantmentPermanent; +import mage.game.Game; +import mage.game.permanent.token.SpiritWorldToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HeiBaiForestGuardian extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent(); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Legendary enchantments you control", xValue); + + public HeiBaiForestGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAR); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Hei Bai enters, reveal cards from the top of your library until you reveal a Shrine card. You may put that card onto the battlefield. Then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new HeiBaiForestGuardianEffect())); + + // {W}{U}{B}{R}{G}, {T}: For each legendary enchantment you control, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new SpiritWorldToken(), xValue) + .setText("for each legendary enchantment you control, create a 1/1 colorless Spirit creature " + + "token with \"This token can't block or be blocked by non-Spirit creatures.\""), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability.addHint(hint)); + } + + private HeiBaiForestGuardian(final HeiBaiForestGuardian card) { + super(card); + } + + @Override + public HeiBaiForestGuardian copy() { + return new HeiBaiForestGuardian(this); + } +} + +class HeiBaiForestGuardianEffect extends OneShotEffect { + + HeiBaiForestGuardianEffect() { + super(Outcome.Benefit); + staticText = "reveal cards from the top of your library until you reveal a Shrine card. " + + "You may put that card onto the battlefield. Then shuffle."; + } + + private HeiBaiForestGuardianEffect(final HeiBaiForestGuardianEffect effect) { + super(effect); + } + + @Override + public HeiBaiForestGuardianEffect copy() { + return new HeiBaiForestGuardianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Card card = getCard(player, cards, game, source); + player.revealCards(source, cards, game); + if (card != null && player.chooseUse( + Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield?", source, game + )) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + player.shuffleLibrary(source, game); + return true; + } + + private static Card getCard(Player player, Cards cards, Game game, Ability source) { + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (card.hasSubtype(SubType.SHRINE, game)) { + return card; + } + } + return null; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeirOfFalkenrath.java b/Mage.Sets/src/mage/cards/h/HeirOfFalkenrath.java index 2074046e6be..36ffd9f815c 100644 --- a/Mage.Sets/src/mage/cards/h/HeirOfFalkenrath.java +++ b/Mage.Sets/src/mage/cards/h/HeirOfFalkenrath.java @@ -1,35 +1,41 @@ - package mage.cards.h; -import java.util.UUID; -import mage.MageInt; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** * * @author fireshoes */ -public final class HeirOfFalkenrath extends CardImpl { +public final class HeirOfFalkenrath extends TransformingDoubleFacedCard { public HeirOfFalkenrath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{1}{B}", + "Heir to the Night", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.BERSERKER}, "B" + ); - this.secondSideCardClazz = mage.cards.h.HeirToTheNight.class; + // Heir of Falkenrath + this.getLeftHalfCard().setPT(2, 1); // Discard a card: Transform Heir of Falkenrath. Activate this ability only once each turn. - this.addAbility(new TransformAbility()); - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new TransformSourceEffect(), new DiscardCardCost())); + this.getLeftHalfCard().addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new TransformSourceEffect(), new DiscardCardCost())); + + // Heir to the Night + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private HeirOfFalkenrath(final HeirOfFalkenrath card) { diff --git a/Mage.Sets/src/mage/cards/h/HeirToTheNight.java b/Mage.Sets/src/mage/cards/h/HeirToTheNight.java deleted file mode 100644 index ca92f5f234e..00000000000 --- a/Mage.Sets/src/mage/cards/h/HeirToTheNight.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.h; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class HeirToTheNight extends CardImpl { - - public HeirToTheNight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.BERSERKER); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private HeirToTheNight(final HeirToTheNight card) { - super(card); - } - - @Override - public HeirToTheNight copy() { - return new HeirToTheNight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HeirloomMirror.java b/Mage.Sets/src/mage/cards/h/HeirloomMirror.java index 69323e07bc4..75d8f78e3e6 100644 --- a/Mage.Sets/src/mage/cards/h/HeirloomMirror.java +++ b/Mage.Sets/src/mage/cards/h/HeirloomMirror.java @@ -2,40 +2,44 @@ package mage.cards.h; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.MillCardsControllerEffect; -import mage.abilities.effects.common.RemoveAllCountersSourceEffect; -import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.*; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class HeirloomMirror extends CardImpl { +public final class HeirloomMirror extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.RITUAL, 3); public HeirloomMirror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); - - this.secondSideCardClazz = mage.cards.i.InheritedFiend.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{B}", + "Inherited Fiend", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); + // Heirloom Mirror // {1}, {T}, Pay 1 life, Discard a card: Draw a card, mill a card, then put a ritual counter on Heirloom Mirror. Then if it has 3 or more ritual counters on it, remove them and transform it. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new PayLifeCost(1)); @@ -44,9 +48,21 @@ public final class HeirloomMirror extends CardImpl { ability.addEffect(new AddCountersSourceEffect(CounterType.RITUAL.createInstance()).concatBy(", then")); ability.addEffect(new ConditionalOneShotEffect( new RemoveAllCountersSourceEffect(CounterType.RITUAL), condition, - "Then if it has 3 or more ritual counters on it, remove them and transform it" + "Then if it has three or more ritual counters on it, remove them and transform it" ).addEffect(new TransformSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Inherited Fiend + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // {2}{B}: Exile target creature card from a graveyard. Put a +1/+1 counter on Inherited Fiend. + Ability backAbility = new SimpleActivatedAbility(new ExileTargetEffect(), new ManaCostsImpl<>("{2}{B}")); + backAbility.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).concatBy(".")); + backAbility.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); + this.getRightHalfCard().addAbility(backAbility); } private HeirloomMirror(final HeirloomMirror card) { diff --git a/Mage.Sets/src/mage/cards/h/HeliodTheRadiantDawn.java b/Mage.Sets/src/mage/cards/h/HeliodTheRadiantDawn.java index 992a028c466..ca94d277ff9 100644 --- a/Mage.Sets/src/mage/cards/h/HeliodTheRadiantDawn.java +++ b/Mage.Sets/src/mage/cards/h/HeliodTheRadiantDawn.java @@ -1,49 +1,66 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterEnchantmentCard; +import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; +import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import mage.watchers.common.CardsDrawnThisTurnWatcher; import java.util.UUID; -public class HeliodTheRadiantDawn extends CardImpl { +public class HeliodTheRadiantDawn extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterEnchantmentCard("enchantment card that isn't a God"); + private static final FilterCard flashFilter = new FilterNonlandCard("spells"); static { filter.add(Predicates.not(SubType.GOD.getPredicate())); } public HeliodTheRadiantDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{2}{W}{W}"); - this.supertype.add(SuperType.LEGENDARY); - this.addSubType(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.h.HeliodTheWarpedEclipse.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.GOD}, "{2}{W}{W}", + "Heliod, the Warped Eclipse", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.GOD}, "WU" + ); + + // Heliod, the Radiant Dawn + this.getLeftHalfCard().setPT(4, 4); // When Heliod, the Radiant Dawn enters the battlefield, return target enchantment card that isn't a God from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); ability.addTarget(new TargetCardInYourGraveyard(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {3}{U/P}: Transform Heliod, the Radiant Dawn. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{U/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{U/P}"))); + + // Heliod, the Warped Eclipse + this.getRightHalfCard().setPT(4, 6); + + // You may cast spells as though they had flash. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CastAsThoughItHadFlashAllEffect(Duration.WhileOnBattlefield, flashFilter))); + + // Spells you cast cost {1} less to cast for each card your opponents have drawn this turn. + Ability ability2 = new SimpleStaticAbility(new HeliodTheWarpedEclipseEffect()); + ability2.addWatcher(new CardsDrawnThisTurnWatcher()); + this.getRightHalfCard().addAbility(ability2); } private HeliodTheRadiantDawn(final HeliodTheRadiantDawn card) { @@ -55,3 +72,45 @@ public class HeliodTheRadiantDawn extends CardImpl { return new HeliodTheRadiantDawn(this); } } + +class HeliodTheWarpedEclipseEffect extends CostModificationEffectImpl { + + HeliodTheWarpedEclipseEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "spells you cast cost {1} less to cast for each card your opponents have drawn this turn"; + } + + private HeliodTheWarpedEclipseEffect(final HeliodTheWarpedEclipseEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardsDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsDrawnThisTurnWatcher.class); + if (watcher == null) { + return false; + } + int amount = game + .getOpponents(source.getControllerId()) + .stream() + .mapToInt(watcher::getCardsDrawnThisTurn) + .sum(); + if (amount < 1) { + return false; + } + CardUtil.adjustCost((SpellAbility) abilityToModify, amount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && game.getCard(abilityToModify.getSourceId()) != null + && abilityToModify.isControlledBy(source.getControllerId()); + } + + @Override + public HeliodTheWarpedEclipseEffect copy() { + return new HeliodTheWarpedEclipseEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeliodTheWarpedEclipse.java b/Mage.Sets/src/mage/cards/h/HeliodTheWarpedEclipse.java deleted file mode 100644 index 712aa244fb9..00000000000 --- a/Mage.Sets/src/mage/cards/h/HeliodTheWarpedEclipse.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.common.FilterNonlandCard; -import mage.game.Game; -import mage.util.CardUtil; -import mage.watchers.common.CardsDrawnThisTurnWatcher; - -import java.util.UUID; - -public class HeliodTheWarpedEclipse extends CardImpl { - - private static final FilterCard filter = new FilterNonlandCard("spells"); - - public HeliodTheWarpedEclipse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - this.color.setWhite(true); - this.color.setBlue(true); - this.supertype.add(SuperType.LEGENDARY); - this.addSubType(SubType.PHYREXIAN); - this.addSubType(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(6); - this.nightCard = true; - - // You may cast spells as though they had flash. - this.addAbility(new SimpleStaticAbility(new CastAsThoughItHadFlashAllEffect(Duration.WhileOnBattlefield, filter))); - - // Spells you cast cost {1} less to cast for each card your opponents have drawn this turn. - this.addAbility(new SimpleStaticAbility(new HeliodTheWarpedEclipseEffect())); - } - - private HeliodTheWarpedEclipse(final HeliodTheWarpedEclipse card) { - super(card); - } - - @Override - public HeliodTheWarpedEclipse copy() { - return new HeliodTheWarpedEclipse(this); - } -} - -class HeliodTheWarpedEclipseEffect extends CostModificationEffectImpl { - - HeliodTheWarpedEclipseEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "spells you cast cost {1} less to cast for each card your opponents have drawn this turn"; - } - - private HeliodTheWarpedEclipseEffect(final HeliodTheWarpedEclipseEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardsDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsDrawnThisTurnWatcher.class); - if (watcher == null) { - return false; - } - int amount = game - .getOpponents(source.getControllerId()) - .stream() - .mapToInt(watcher::getCardsDrawnThisTurn) - .sum(); - if (amount < 1) { - return false; - } - CardUtil.adjustCost((SpellAbility) abilityToModify, amount); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - return abilityToModify instanceof SpellAbility - && game.getCard(abilityToModify.getSourceId()) != null - && abilityToModify.isControlledBy(source.getControllerId()); - } - - @Override - public HeliodTheWarpedEclipseEffect copy() { - return new HeliodTheWarpedEclipseEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java index 527669c7bd4..97ae001b9d0 100644 --- a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java +++ b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java @@ -33,7 +33,7 @@ public final class HellfireMongrel extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Hellfire Mongrel deals 2 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/h/HenrikaDomnathi.java b/Mage.Sets/src/mage/cards/h/HenrikaDomnathi.java index 2b2b78e162c..c85473cec50 100644 --- a/Mage.Sets/src/mage/cards/h/HenrikaDomnathi.java +++ b/Mage.Sets/src/mage/cards/h/HenrikaDomnathi.java @@ -1,41 +1,57 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.SacrificeAllEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.hint.common.ModesAlreadyUsedHint; +import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; import java.util.UUID; /** * @author TheElk801 */ -public final class HenrikaDomnathi extends CardImpl { +public final class HenrikaDomnathi extends TransformingDoubleFacedCard { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each creature you control with flying, deathtouch, and/or lifelink"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + filter.add(Predicates.or( + new AbilityPredicate(FlyingAbility.class), + new AbilityPredicate(DeathtouchAbility.class), + new AbilityPredicate(LifelinkAbility.class) + )); + } public HenrikaDomnathi(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{B}{B}", + "Henrika, Infernal Seer", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.h.HenrikaInfernalSeer.class; + // Henrika Domnathi + this.getLeftHalfCard().setPT(1, 3); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // At the beginning of combat on your turn, choose one that hasn't been chosen — // • Each player sacrifices a creature. @@ -51,10 +67,26 @@ public final class HenrikaDomnathi extends CardImpl { // • Transform Henrika Domnathi. ability.addMode(new Mode(new TransformSourceEffect()).setModeTag("transform")); - this.addAbility(new TransformAbility()); ability.addHint(ModesAlreadyUsedHint.instance); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Henrika, Infernal Seer + this.getRightHalfCard().setPT(3, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // {1}{B}{B}: Each creature you control with flying, deathtouch, and/or lifelink gets +1/+0 until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new BoostAllEffect( + 1, 0, Duration.EndOfTurn, filter, false + ), new ManaCostsImpl<>("{1}{B}{B}"))); } private HenrikaDomnathi(final HenrikaDomnathi card) { diff --git a/Mage.Sets/src/mage/cards/h/HenrikaInfernalSeer.java b/Mage.Sets/src/mage/cards/h/HenrikaInfernalSeer.java deleted file mode 100644 index fce0036801d..00000000000 --- a/Mage.Sets/src/mage/cards/h/HenrikaInfernalSeer.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AbilityPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HenrikaInfernalSeer extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each creature you control with flying, deathtouch, and/or lifelink"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(Predicates.or( - new AbilityPredicate(FlyingAbility.class), - new AbilityPredicate(DeathtouchAbility.class), - new AbilityPredicate(LifelinkAbility.class) - )); - } - - public HenrikaInfernalSeer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // {1}{B}{B}: Each creature you control with flying, deathtouch, and/or lifelink gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostAllEffect( - 1, 0, Duration.EndOfTurn, filter, false - ), new ManaCostsImpl<>("{1}{B}{B}"))); - } - - private HenrikaInfernalSeer(final HenrikaInfernalSeer card) { - super(card); - } - - @Override - public HenrikaInfernalSeer copy() { - return new HenrikaInfernalSeer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HerbologyInstructor.java b/Mage.Sets/src/mage/cards/h/HerbologyInstructor.java index 826ab7f6688..4b3be096b87 100644 --- a/Mage.Sets/src/mage/cards/h/HerbologyInstructor.java +++ b/Mage.Sets/src/mage/cards/h/HerbologyInstructor.java @@ -1,39 +1,55 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 HerbologyInstructor extends CardImpl { +public final class HerbologyInstructor extends TransformingDoubleFacedCard { public HerbologyInstructor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK, SubType.DRUID}, "{1}{G}", + "Malady Invoker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.TREEFOLK}, "BG" + ); - this.subtype.add(SubType.TREEFOLK); - this.subtype.add(SubType.DRUID); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.m.MaladyInvoker.class; + // Herbology Instructor + this.getLeftHalfCard().setPT(1, 3); // When Herbology Instructor enters the battlefield, you gain 3 life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); // {6}{B/P}: Transform Herbology Instructor. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{B/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{B/P}"))); + + // Malady Invoker + this.getRightHalfCard().setPT(3, 3); + + // When this creature transforms into Malady Invoker, target creature an opponent controls gets -0/-X until end of turn, where X is Malady Invoker's power. + Ability ability = new TransformIntoSourceTriggeredAbility(new BoostTargetEffect( + StaticValue.get(0), new SignInversionDynamicValue(SourcePermanentPowerValue.NOT_NEGATIVE), Duration.EndOfTurn + ).setText("target creature an opponent controls gets -0/-X until end of turn, where X is {this}'s power")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.getRightHalfCard().addAbility(ability); } private HerbologyInstructor(final HerbologyInstructor card) { diff --git a/Mage.Sets/src/mage/cards/h/HermitOfTheNatterknolls.java b/Mage.Sets/src/mage/cards/h/HermitOfTheNatterknolls.java index ede6c5f95e4..f041fc3c33a 100644 --- a/Mage.Sets/src/mage/cards/h/HermitOfTheNatterknolls.java +++ b/Mage.Sets/src/mage/cards/h/HermitOfTheNatterknolls.java @@ -1,13 +1,12 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -17,25 +16,36 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class HermitOfTheNatterknolls extends CardImpl { +public final class HermitOfTheNatterknolls extends TransformingDoubleFacedCard { public HermitOfTheNatterknolls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{G}", + "Lone Wolf of the Natterknolls", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.l.LoneWolfOfTheNatterknolls.class; + // Hermit of the Natterknolls + this.getLeftHalfCard().setPT(2, 3); // Whenever an opponent casts a spell during your turn, draw a card. - this.addAbility(new SpellCastOpponentTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastOpponentTriggeredAbility( new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_SPELL_A, false ).withTriggerCondition(MyTurnCondition.instance)); // At the beginning of each upkeep, if no spells were cast last turn, transform Hermit of the Natterknolls. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Lone Wolf of the Natterknolls + this.getRightHalfCard().setPT(3, 5); + + // Whenever an opponent cast a spell during your turn, draw two cards. + this.getRightHalfCard().addAbility(new SpellCastOpponentTriggeredAbility( + new DrawCardSourceControllerEffect(2), StaticFilters.FILTER_SPELL_A, false + ).withTriggerCondition(MyTurnCondition.instance)); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lone Wolf of the Natterknolls. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private HermitOfTheNatterknolls(final HermitOfTheNatterknolls card) { diff --git a/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java b/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java new file mode 100644 index 00000000000..88a1a4689aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HermiticHerbalist.java @@ -0,0 +1,53 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HermiticHerbalist extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("Lesson spells"); + + static { + filter.add(SubType.LESSON.getPredicate()); + } + + public HermiticHerbalist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + + // {T}: Add two mana in any combination of colors. Spend this mana only to cast Lesson spells. + this.addAbility(new ConditionalAnyColorManaAbility( + new TapSourceCost(), 2, new ConditionalSpellManaBuilder(filter), false + )); + } + + private HermiticHerbalist(final HermiticHerbalist card) { + super(card); + } + + @Override + public HermiticHerbalist copy() { + return new HermiticHerbalist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeroesInAHalfShell.java b/Mage.Sets/src/mage/cards/h/HeroesInAHalfShell.java new file mode 100644 index 00000000000..5c5a2b7f899 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeroesInAHalfShell.java @@ -0,0 +1,80 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.MenaceAbility; +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.SetTargetPointer; +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.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HeroesInAHalfShell extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("Mutants, Ninjas, and/or Turtles you control"); + + static { + filter.add(Predicates.or( + SubType.MUTANT.getPredicate(), + SubType.NINJA.getPredicate(), + SubType.TURTLE.getPredicate() + )); + } + + public HeroesInAHalfShell(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever one or more Mutants, Ninjas, and/or Turtles you control deal combat damage to a player, put a +1/+1 counter on each of those creatures and draw a card. + Ability ability = new OneOrMoreCombatDamagePlayerTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on each of those creatures"), + SetTargetPointer.PERMANENT, filter, false + ); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private HeroesInAHalfShell(final HeroesInAHalfShell card) { + super(card); + } + + @Override + public HeroesInAHalfShell copy() { + return new HeroesInAHalfShell(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HiddenRetreat.java b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java index c2e56e51fe5..dc132a96978 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenRetreat.java +++ b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java @@ -8,7 +8,6 @@ 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.game.Game; import mage.game.events.DamageEvent; @@ -58,11 +57,6 @@ class HiddenRetreatEffect extends PreventionEffectImpl { return new HiddenRetreatEffect(this); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return true; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { return (super.applies(event, source, game) diff --git a/Mage.Sets/src/mage/cards/h/HideousFleshwheeler.java b/Mage.Sets/src/mage/cards/h/HideousFleshwheeler.java deleted file mode 100644 index f7b1017e7d3..00000000000 --- a/Mage.Sets/src/mage/cards/h/HideousFleshwheeler.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HideousFleshwheeler extends CardImpl { - - private static final FilterCard filter - = new FilterPermanentCard("permanent card with mana value 2 or less from a graveyard"); - - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); - } - - public HideousFleshwheeler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.RAT); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // When this creature transforms into Hideous FleshwheelerHideous Fleshwheeler, put target permanent card with mana value 2 or less from a graveyard onto the battlefield under your control. - Ability ability = new TransformIntoSourceTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); - ability.addTarget(new TargetCardInGraveyard(filter)); - this.addAbility(ability); - } - - private HideousFleshwheeler(final HideousFleshwheeler card) { - super(card); - } - - @Override - public HideousFleshwheeler copy() { - return new HideousFleshwheeler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java b/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java index 16e6ba35dc0..8b01a26e62e 100644 --- a/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java +++ b/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java @@ -1,26 +1,38 @@ package mage.cards.h; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageSourceTriggeredAbility; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.condition.Condition; 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.abilities.effects.common.LoseGameTargetPlayerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SagaChapter; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; /** * @author TheElk801 */ -public final class HidetsuguConsumesAll extends CardImpl { +public final class HidetsuguConsumesAll extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterNonlandPermanent(); @@ -29,26 +41,41 @@ public final class HidetsuguConsumesAll extends CardImpl { } 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; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{B}{R}", + "Vessel of the All-Consuming", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.OGRE, SubType.SHAMAN}, "BR" + ); + // Hidetsugu Consumes All // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Destroy each nonland permanent with mana value 1 or less. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new DestroyAllEffect(filter) + sagaAbility.addChapterEffect(this.getLeftHalfCard(), 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + sagaAbility.addWatcher(VesselOfTheAllConsumingWatcher.makeWatcher()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility, mage.cards.v.VesselOfTheAllConsuming.makeWatcher()); + // Vessel of the All-Consuming + this.getRightHalfCard().setPT(3, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever Vessel of the All-Consuming deals damage, put a +1/+1 counter on it. + this.getRightHalfCard().addAbility(new DealsDamageSourceTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + + // 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.getRightHalfCard().addAbility(new DealsDamageToAPlayerTriggeredAbility( + new LoseGameTargetPlayerEffect().setText("they lose the game"), false, true + ).withInterveningIf(VesselOfTheAllConsumingCondition.instance)); } private HidetsuguConsumesAll(final HidetsuguConsumesAll card) { @@ -60,3 +87,60 @@ public final class HidetsuguConsumesAll extends CardImpl { return new HidetsuguConsumesAll(this); } } + +enum VesselOfTheAllConsumingCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return VesselOfTheAllConsumingWatcher.checkPermanent(game, source); + } + + @Override + public String toString() { + return "it has dealt 10 or more damage to that player this turn"; + } +} + +class VesselOfTheAllConsumingWatcher extends Watcher { + + private final Map, Integer> morMap = 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) { + int damage = event.getAmount(); + morMap.compute(new AbstractMap.SimpleImmutableEntry(new MageObjectReference(permanent, game), event.getTargetId()), + (u, i) -> i == null ? damage : Integer.sum(i, damage)); + } + } + + @Override + public void reset() { + super.reset(); + morMap.clear(); + } + + static Watcher makeWatcher() { + return new VesselOfTheAllConsumingWatcher(); + } + + static boolean checkPermanent(Game game, Ability source) { + VesselOfTheAllConsumingWatcher watcher = game.getState().getWatcher(VesselOfTheAllConsumingWatcher.class); + if (watcher == null) { + return false; + } + AbstractMap.SimpleImmutableEntry key = new AbstractMap.SimpleImmutableEntry<>( + new MageObjectReference(game.getPermanent(source.getSourceId()), game), + source.getEffects().get(0).getTargetPointer().getFirst(game, source)); + return watcher.morMap.getOrDefault(key, 0) >= 10; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HighPerfectMorcant.java b/Mage.Sets/src/mage/cards/h/HighPerfectMorcant.java new file mode 100644 index 00000000000..ce4a60cc452 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HighPerfectMorcant.java @@ -0,0 +1,92 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.effects.keyword.BlightControllerEffect; +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.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HighPerfectMorcant extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ELF, "Elf"); + private static final FilterControlledPermanent filter2 + = new FilterControlledPermanent(SubType.ELF, "untapped Elves you control"); + + static { + filter2.add(TappedPredicate.UNTAPPED); + } + + public HighPerfectMorcant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever High Perfect Morcant or another Elf you control enters, each opponent blights 1. + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( + new HighPerfectMorcantEffect(), filter, false, true + )); + + // Tap three untapped Elves you control: Proliferate. Activate only as a sorcery. + this.addAbility(new ActivateAsSorceryActivatedAbility( + new ProliferateEffect(), new TapTargetCost(3, filter2) + )); + } + + private HighPerfectMorcant(final HighPerfectMorcant card) { + super(card); + } + + @Override + public HighPerfectMorcant copy() { + return new HighPerfectMorcant(this); + } +} + +class HighPerfectMorcantEffect extends OneShotEffect { + + HighPerfectMorcantEffect() { + super(Outcome.Benefit); + staticText = "each opponent blights 1. (They each put a -1/-1 counter on a creature they control.)"; + } + + private HighPerfectMorcantEffect(final HighPerfectMorcantEffect effect) { + super(effect); + } + + @Override + public HighPerfectMorcantEffect copy() { + return new HighPerfectMorcantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + BlightControllerEffect.doBlight(opponent, 1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HinterlandHermit.java b/Mage.Sets/src/mage/cards/h/HinterlandHermit.java index e376e0ebdea..12fe9a552e1 100644 --- a/Mage.Sets/src/mage/cards/h/HinterlandHermit.java +++ b/Mage.Sets/src/mage/cards/h/HinterlandHermit.java @@ -1,11 +1,13 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import java.util.UUID; @@ -13,21 +15,29 @@ import java.util.UUID; /** * @author BetaSteward */ -public final class HinterlandHermit extends CardImpl { +public final class HinterlandHermit extends TransformingDoubleFacedCard { public HinterlandHermit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{R}", + "Hinterland Scourge", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.h.HinterlandScourge.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(1); + // Hinterland Hermit + this.getLeftHalfCard().setPT(2, 1); // At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Hermit. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Hinterland Scourge + this.getRightHalfCard().setPT(3, 2); + + // Hinterland Scourge must be blocked if able. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Hinterland Scourge. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private HinterlandHermit(final HinterlandHermit card) { diff --git a/Mage.Sets/src/mage/cards/h/HinterlandLogger.java b/Mage.Sets/src/mage/cards/h/HinterlandLogger.java index 51df4a09630..ffd994ac6ab 100644 --- a/Mage.Sets/src/mage/cards/h/HinterlandLogger.java +++ b/Mage.Sets/src/mage/cards/h/HinterlandLogger.java @@ -1,10 +1,10 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,20 +13,29 @@ import java.util.UUID; /** * @author fireshoes */ -public final class HinterlandLogger extends CardImpl { +public final class HinterlandLogger extends TransformingDoubleFacedCard { public HinterlandLogger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}", + "Timber Shredder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.t.TimberShredder.class; + this.getLeftHalfCard().setPT(2, 1); + this.getRightHalfCard().setPT(4, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Logger. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Timber Shredder + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); + + } private HinterlandLogger(final HinterlandLogger card) { diff --git a/Mage.Sets/src/mage/cards/h/HinterlandScourge.java b/Mage.Sets/src/mage/cards/h/HinterlandScourge.java deleted file mode 100644 index cd0c9e0c8ba..00000000000 --- a/Mage.Sets/src/mage/cards/h/HinterlandScourge.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; -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 BetaSteward - */ -public final class HinterlandScourge extends CardImpl { - - public HinterlandScourge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card of Hinterland Hermit - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); - - // Hinterland Scourge must be blocked if able. - this.addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Hinterland Scourge. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private HinterlandScourge(final HinterlandScourge card) { - super(card); - } - - @Override - public HinterlandScourge copy() { - return new HinterlandScourge(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java b/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java new file mode 100644 index 00000000000..a42a9636017 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HogMonkeyRampage.java @@ -0,0 +1,67 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HogMonkeyRampage extends CardImpl { + + public HogMonkeyRampage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R/G}"); + + // Choose target creature you control and target creature an opponent controls. Put a +1/+1 counter on the creature you control if it has power 4 or greater. Then those creatures fight each other. + this.getSpellAbility().addEffect(new HogMonkeyRampageEffect()); + this.getSpellAbility().addEffect(new FightTargetsEffect().setText("Then those creatures fight each other")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + } + + private HogMonkeyRampage(final HogMonkeyRampage card) { + super(card); + } + + @Override + public HogMonkeyRampage copy() { + return new HogMonkeyRampage(this); + } +} + +class HogMonkeyRampageEffect extends OneShotEffect { + + HogMonkeyRampageEffect() { + super(Outcome.Benefit); + staticText = "choose target creature you control and target creature an opponent controls. " + + "Put a +1/+1 counter on the creature you control if it has power 4 or greater"; + } + + private HogMonkeyRampageEffect(final HogMonkeyRampageEffect effect) { + super(effect); + } + + @Override + public HogMonkeyRampageEffect copy() { + return new HogMonkeyRampageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null + && permanent.getPower().getValue() >= 4 + && permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java b/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java deleted file mode 100644 index efe1f2b1abb..00000000000 --- a/Mage.Sets/src/mage/cards/h/HollowhengeHuntmaster.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.NightboundAbility; -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 HollowhengeHuntmaster extends CardImpl { - - public HollowhengeHuntmaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setGreen(true); - this.nightCard = true; - - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - - // Other permanents you control have hexproof. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - HexproofAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENTS, true - ))); - - // At the beginning of combat on your turn, put two +1/+1 counters on each creature you control. - this.addAbility(new BeginningOfCombatTriggeredAbility( - new AddCountersAllEffect( - CounterType.P1P1.createInstance(2), - StaticFilters.FILTER_CONTROLLED_CREATURE - ) - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private HollowhengeHuntmaster(final HollowhengeHuntmaster card) { - super(card); - } - - @Override - public HollowhengeHuntmaster copy() { - return new HollowhengeHuntmaster(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HolyFrazzleCannon.java b/Mage.Sets/src/mage/cards/h/HolyFrazzleCannon.java deleted file mode 100644 index 60301909b4f..00000000000 --- a/Mage.Sets/src/mage/cards/h/HolyFrazzleCannon.java +++ /dev/null @@ -1,82 +0,0 @@ -package mage.cards.h; - -import mage.abilities.Ability; -import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -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.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HolyFrazzleCannon extends CardImpl { - - public HolyFrazzleCannon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.subtype.add(SubType.EQUIPMENT); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever equipped creature attacks, put a +1/+1 counter on that creature and each other creature you control that shares a creature type with it. - this.addAbility(new AttacksAttachedTriggeredAbility( - new HolyFrazzleCannonEffect(), AttachmentType.EQUIPMENT, - false, SetTargetPointer.PERMANENT - )); - - // Equip {1} - this.addAbility(new EquipAbility(1, false)); - } - - private HolyFrazzleCannon(final HolyFrazzleCannon card) { - super(card); - } - - @Override - public HolyFrazzleCannon copy() { - return new HolyFrazzleCannon(this); - } -} - -class HolyFrazzleCannonEffect extends OneShotEffect { - - HolyFrazzleCannonEffect() { - super(Outcome.Benefit); - staticText = "put a +1/+1 counter on that creature and " + - "each other creature you control that shares a creature type with it"; - } - - private HolyFrazzleCannonEffect(final HolyFrazzleCannonEffect effect) { - super(effect); - } - - @Override - public HolyFrazzleCannonEffect copy() { - return new HolyFrazzleCannonEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - for (Permanent creature : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game - )) { - if (creature.equals(permanent) || permanent.shareCreatureTypes(game, creature)) { - creature.addCounters(CounterType.P1P1.createInstance(), source, game); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java b/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java index 33833f95671..e2a8022bcc2 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java @@ -1,20 +1,15 @@ - - package mage.cards.h; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.MultipliedValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -23,19 +18,15 @@ import java.util.UUID; */ public final class HondenOfCleansingFire extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); + private static final DynamicValue xValue = new MultipliedValue(ShrinesYouControlCount.FOR_EACH, 2); public HondenOfCleansingFire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); - // At the beginning of your upkeep, you gain 2 life for each Shrine you control. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(new MultipliedValue(xValue, 2))).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(xValue)).addHint(ShrinesYouControlCount.getHint())); } private HondenOfCleansingFire(final HondenOfCleansingFire card) { diff --git a/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java b/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java index aba3e7383c7..d3951458985 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java @@ -1,39 +1,33 @@ package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class HondenOfInfiniteRage extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public HondenOfInfiniteRage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); // At the beginning of your upkeep, Honden of Infinite Rage deals damage to any target equal to the number of Shrines you control. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DamageTargetEffect(xValue)).addHint(hint); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new DamageTargetEffect(ShrinesYouControlCount.WHERE_X) + .setText("{this} deals damage to any target equal to the number of Shrines you control") + ).addHint(ShrinesYouControlCount.getHint()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java b/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java index a454a61824e..e387bb9e671 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java @@ -1,19 +1,13 @@ - - package mage.cards.h; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.SpiritToken; import java.util.UUID; @@ -23,17 +17,14 @@ import java.util.UUID; */ public final class HondenOfLifesWeb extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public HondenOfLifesWeb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new SpiritToken(), xValue)).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new SpiritToken(), ShrinesYouControlCount.FOR_EACH) + ).addHint(ShrinesYouControlCount.getHint())); } private HondenOfLifesWeb(final HondenOfLifesWeb card) { diff --git a/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java b/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java index 6741ac4a502..eebc9b261c6 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java @@ -1,38 +1,30 @@ package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** * @author Loki */ public final class HondenOfNightsReach extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public HondenOfNightsReach(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); // At the beginning of your upkeep, target opponent discards a card for each Shrine you control. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DiscardTargetEffect(xValue)).addHint(hint); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DiscardTargetEffect(ShrinesYouControlCount.FOR_EACH)).addHint(ShrinesYouControlCount.getHint()); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java b/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java index b033db25dbe..2b096f91c2f 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java @@ -1,19 +1,13 @@ - - package mage.cards.h; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; @@ -22,19 +16,13 @@ import java.util.UUID; */ public final class HondenOfSeeingWinds extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - new FilterControlledPermanent(SubType.SHRINE) - ); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - public HondenOfSeeingWinds(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); - // At the beginning of your upkeep, draw a card for each Shrine you control. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(xValue)).addHint(hint)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(ShrinesYouControlCount.FOR_EACH)).addHint(ShrinesYouControlCount.getHint())); } private HondenOfSeeingWinds(final HondenOfSeeingWinds card) { diff --git a/Mage.Sets/src/mage/cards/h/HonestWork.java b/Mage.Sets/src/mage/cards/h/HonestWork.java new file mode 100644 index 00000000000..3d79617209b --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HonestWork.java @@ -0,0 +1,153 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.mana.ColorlessManaAbility; +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.TargetOpponentsCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HonestWork extends CardImpl { + + public HonestWork(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature an opponent controls + TargetPermanent auraTarget = new TargetOpponentsCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // When this Aura enters, tap enchanted creature and remove all counters from it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new HonestWorkCountersEffect()); + this.addAbility(ability); + + // Enchanted creature loses all abilities and is a Citizen with base power and toughness 1/1 and "{T}: Add {C}" named Humble Merchant. + this.addAbility(new SimpleStaticAbility(new HonestWorkAbilityEffect())); + } + + private HonestWork(final HonestWork card) { + super(card); + } + + @Override + public HonestWork copy() { + return new HonestWork(this); + } +} + +class HonestWorkCountersEffect extends OneShotEffect { + + HonestWorkCountersEffect() { + super(Outcome.Benefit); + staticText = "and remove all counters from it"; + } + + private HonestWorkCountersEffect(final HonestWorkCountersEffect effect) { + super(effect); + } + + @Override + public HonestWorkCountersEffect copy() { + return new HonestWorkCountersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .ofNullable((Permanent) getValue("permanentEnteredBattlefield")) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .filter(permanent -> permanent.removeAllCounters(source, game) > 0) + .isPresent(); + } +} + +class HonestWorkAbilityEffect extends ContinuousEffectImpl { + + HonestWorkAbilityEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "enchanted creature loses all abilities and is a Citizen " + + "with base power and toughness 1/1 and \"{T}: Add {C}\" named Humble Merchant."; + } + + private HonestWorkAbilityEffect(final HonestWorkAbilityEffect effect) { + super(effect); + } + + @Override + public HonestWorkAbilityEffect copy() { + return new HonestWorkAbilityEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .orElse(null); + if (permanent == null) { + return false; + } + switch (layer) { + case TextChangingEffects_3: + permanent.setName("Humble Merchant"); + return true; + case TypeChangingEffects_4: + permanent.removeAllCreatureTypes(); + permanent.addSubType(game, SubType.CITIZEN); + return true; + case AbilityAddingRemovingEffects_6: + permanent.removeAllAbilities(source.getSourceId(), game); + permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.SetPT_7b) { + return false; + } + permanent.getPower().setModifiedBaseValue(1); + permanent.getToughness().setModifiedBaseValue(1); + return true; + default: + return false; + } + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TextChangingEffects_3: + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + default: + return false; + } + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java b/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java deleted file mode 100644 index b63a9bb5b09..00000000000 --- a/Mage.Sets/src/mage/cards/h/HookHauntDrifter.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -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 HookHauntDrifter extends CardImpl { - - public HookHauntDrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private HookHauntDrifter(final HookHauntDrifter card) { - super(card); - } - - @Override - public HookHauntDrifter copy() { - return new HookHauntDrifter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HookSwords.java b/Mage.Sets/src/mage/cards/h/HookSwords.java new file mode 100644 index 00000000000..18ad91d00d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HookSwords.java @@ -0,0 +1,58 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.CreateTokenAttachSourceEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +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.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HookSwords extends CardImpl { + + public HookSwords(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R/W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When this Equipment enters, create a 1/1 white Ally creature token, then attach this Equipment to it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenAttachSourceEffect(new AllyToken()))); + + // During your turn, equipped creature gets +1/+1 and has first strike. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostEquippedEffect(1, 1), MyTurnCondition.instance, + "during your turn, equipped creature gets +1/+1" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT), + MyTurnCondition.instance, "and has first strike" + )); + this.addAbility(ability); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private HookSwords(final HookSwords card) { + super(card); + } + + @Override + public HookSwords copy() { + return new HookSwords(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HookhandMariner.java b/Mage.Sets/src/mage/cards/h/HookhandMariner.java index c2fc61ab523..dd34f90a2eb 100644 --- a/Mage.Sets/src/mage/cards/h/HookhandMariner.java +++ b/Mage.Sets/src/mage/cards/h/HookhandMariner.java @@ -1,9 +1,10 @@ package mage.cards.h; -import mage.MageInt; +import mage.abilities.keyword.DauntAbility; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -12,19 +13,29 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HookhandMariner extends CardImpl { +public final class HookhandMariner extends TransformingDoubleFacedCard { public HookhandMariner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{G}", + "Riphook Raider", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.r.RiphookRaider.class; + // Hookhand Mariner + this.getLeftHalfCard().setPT(4, 4); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Riphook Raider + this.getRightHalfCard().setPT(6, 4); + + // Riphook Raider can't be blocked by creatures with power 2 or less. + this.getRightHalfCard().addAbility(new DauntAbility()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private HookhandMariner(final HookhandMariner card) { diff --git a/Mage.Sets/src/mage/cards/h/HostileHostel.java b/Mage.Sets/src/mage/cards/h/HostileHostel.java index 8e8a5a156c4..8538da2f36c 100644 --- a/Mage.Sets/src/mage/cards/h/HostileHostel.java +++ b/Mage.Sets/src/mage/cards/h/HostileHostel.java @@ -2,42 +2,57 @@ package mage.cards.h; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PhaseOutSourceEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; import java.util.UUID; /** * @author LePwnerer */ -public final class HostileHostel extends CardImpl { +public final class HostileHostel extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.SOUL, 3); public HostileHostel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.secondSideCardClazz = mage.cards.c.CreepingInn.class; + super(ownerId, setInfo, + new CardType[]{CardType.LAND}, new SubType[]{}, "", + "Creeping Inn", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.HORROR, SubType.CONSTRUCT}, "B" + ); + // Hostile Hostel // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); + this.getLeftHalfCard().addAbility(new ColorlessManaAbility()); // {1}, {T}, Sacrifice a creature: Put a soul counter on Hostile Hostel. Then if there are three or more soul counters on it, remove those counters, transform it, then untap it. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility(new AddCountersSourceEffect(CounterType.SOUL.createInstance()), new ManaCostsImpl<>("{1}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); @@ -45,7 +60,17 @@ public final class HostileHostel extends CardImpl { new RemoveAllCountersSourceEffect(CounterType.SOUL), condition, "Then if there are three " + "or more soul counters on it, remove those counters, transform it, then untap it" ).addEffect(new TransformSourceEffect()).addEffect(new UntapSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Creeping Inn + this.getRightHalfCard().setPT(3, 7); + + // Whenever Creeping Inn attacks, you may exile a creature card from your graveyard. + // If you do, each opponent loses X life and you gain X life, where X is the number of creature cards exiled with Creeping Inn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new CreepingInnEffect())); + + // {4}: Creeping Inn phases out. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new PhaseOutSourceEffect(), new ManaCostsImpl<>("{4}"))); } private HostileHostel(final HostileHostel card) { @@ -57,3 +82,54 @@ public final class HostileHostel extends CardImpl { return new HostileHostel(this); } } + +class CreepingInnEffect extends OneShotEffect { + + CreepingInnEffect() { + super(Outcome.Exile); + this.staticText = "you may exile a creature card from your graveyard. " + + "If you do, each opponent loses X life and you gain X life, " + + "where X is the number of creature cards exiled with {this}."; + } + + private CreepingInnEffect(final CreepingInnEffect effect) { + super(effect); + } + + @Override + public CreepingInnEffect copy() { + return new CreepingInnEffect(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) { + UUID exileId = CardUtil.getExileZoneId(game, source); + TargetCardInGraveyard target = new TargetCardInGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + target.withNotTarget(true); + 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; + player.moveCardsToExile(cardChosen, source, game, true, exileId, permanent.getName()); + ExileZone exile = game.getExile().getExileZone(exileId); + if (exile != null) { + for (UUID cardId : exile) { + lifeAmount++; + } + } + for (UUID playerId : game.getOpponents(source.getControllerId())) { + game.getPlayer(playerId).loseLife(lifeAmount, game, source, false); + } + player.gainLife(lifeAmount, game, source); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HoundTamer.java b/Mage.Sets/src/mage/cards/h/HoundTamer.java index 925be3abf19..c546be35ee4 100644 --- a/Mage.Sets/src/mage/cards/h/HoundTamer.java +++ b/Mage.Sets/src/mage/cards/h/HoundTamer.java @@ -1,17 +1,22 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -19,29 +24,60 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HoundTamer extends CardImpl { +public final class HoundTamer extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent("Wolves and Werewolves"); + + static { + filter.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); + } public HoundTamer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{G}", + "Untamed Pup", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.u.UntamedPup.class; + // Hound Tamer + this.getLeftHalfCard().setPT(3, 3); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // {3}{G}: Put a +1/+1 counter on target creature. Ability ability = new SimpleActivatedAbility( new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{3}{G}") ); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Untamed Pup + this.getRightHalfCard().setPT(4, 4); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Other Wolves and Werewolves you control have trample. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ))); + + // {3}{G}: Put a +1/+1 counter on target creature. + Ability backAbility = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{3}{G}") + ); + backAbility.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(backAbility); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private HoundTamer(final HoundTamer card) { diff --git a/Mage.Sets/src/mage/cards/h/HowlingChorus.java b/Mage.Sets/src/mage/cards/h/HowlingChorus.java deleted file mode 100644 index 5d0a033e27b..00000000000 --- a/Mage.Sets/src/mage/cards/h/HowlingChorus.java +++ /dev/null @@ -1,48 +0,0 @@ - -package mage.cards.h; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesWithLessPowerEffect; -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.EldraziHorrorToken; - -/** - * - * @author LevelX2 - */ -public final class HowlingChorus extends CardImpl { - - public HowlingChorus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Creatures with power less than Howling Chorus's power can't block it. - this.addAbility(new SimpleStaticAbility(new CantBeBlockedByCreaturesWithLessPowerEffect())); - - // Whenever Howling Chorus deals combat damage to a player, create a 3/2 colorless Eldrazi Horror creature token. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect(new EldraziHorrorToken()), false)); - } - - private HowlingChorus(final HowlingChorus card) { - super(card); - } - - @Override - public HowlingChorus copy() { - return new HowlingChorus(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HowlpackAlpha.java b/Mage.Sets/src/mage/cards/h/HowlpackAlpha.java deleted file mode 100644 index 2acb47d31d8..00000000000 --- a/Mage.Sets/src/mage/cards/h/HowlpackAlpha.java +++ /dev/null @@ -1,66 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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.filter.predicate.Predicates; -import mage.game.permanent.token.WolfToken; - -import java.util.UUID; - -/** - * @author North, noxx - */ -public final class HowlpackAlpha extends CardImpl { - - private static final FilterCreaturePermanent filter - = new FilterCreaturePermanent("each other creature you control that's a Werewolf or a Wolf"); - - static { - filter.add(Predicates.or( - SubType.WEREWOLF.getPredicate(), - SubType.WOLF.getPredicate() - )); - } - - public HowlpackAlpha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.color.setGreen(true); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - // Other Werewolf and Wolf creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 1, 1, Duration.WhileOnBattlefield, filter, true - ))); - - // At the beginning of your end step, create a 2/2 green Wolf creature token. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new WolfToken()))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Howlpack Alpha. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private HowlpackAlpha(final HowlpackAlpha card) { - super(card); - } - - @Override - public HowlpackAlpha copy() { - return new HowlpackAlpha(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java b/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java deleted file mode 100644 index f0ee5d31421..00000000000 --- a/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealtDamageAnyTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.SavedDamageValue; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.common.TargetAnyTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HowlpackAvenger extends CardImpl { - - public HowlpackAvenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Whenever a permanent you control is dealt damage, Howlpack Avenger deals that much damage to any target. - Ability ability = new DealtDamageAnyTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH), - StaticFilters.FILTER_CONTROLLED_A_PERMANENT, SetTargetPointer.NONE, false); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - - // {1}{R}: Howlpack Avenger gets +2/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( - 2, 0, Duration.EndOfTurn - ), new ManaCostsImpl<>("{1}{R}"))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private HowlpackAvenger(final HowlpackAvenger card) { - super(card); - } - - @Override - public HowlpackAvenger copy() { - return new HowlpackAvenger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HowlpackOfEstwald.java b/Mage.Sets/src/mage/cards/h/HowlpackOfEstwald.java deleted file mode 100644 index 42f61342450..00000000000 --- a/Mage.Sets/src/mage/cards/h/HowlpackOfEstwald.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class HowlpackOfEstwald extends CardImpl { - - public HowlpackOfEstwald(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(4); - this.toughness = new MageInt(6); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Howlpack of Estwald. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private HowlpackOfEstwald(final HowlpackOfEstwald card) { - super(card); - } - - @Override - public HowlpackOfEstwald copy() { - return new HowlpackOfEstwald(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HowlpackPiper.java b/Mage.Sets/src/mage/cards/h/HowlpackPiper.java index 577c869a305..1cd474f789b 100644 --- a/Mage.Sets/src/mage/cards/h/HowlpackPiper.java +++ b/Mage.Sets/src/mage/cards/h/HowlpackPiper.java @@ -1,20 +1,19 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.CantBeCounteredSourceAbility; +import mage.abilities.common.TransformsOrEntersTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; 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.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -28,29 +27,41 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HowlpackPiper extends CardImpl { +public final class HowlpackPiper extends TransformingDoubleFacedCard { public HowlpackPiper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{G}", + "Wildsong Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.w.WildsongHowler.class; + // Howlpack Piper + this.getLeftHalfCard().setPT(2, 2); // This spell can't be countered. - this.addAbility(new CantBeCounteredSourceAbility()); + this.getLeftHalfCard().addAbility(new CantBeCounteredSourceAbility()); // {1}{G}, {T}: You may put a creature card from your hand onto the battlefield. If it's a Wolf or Werewolf, untap Howlpack Piper. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility( new HowlpackPiperEffect(), new ManaCostsImpl<>("{1}{G}") ); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Wildsong Howler + this.getRightHalfCard().setPT(4, 4); + + // 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.getRightHalfCard().addAbility(new TransformsOrEntersTriggeredAbility( + new LookLibraryAndPickControllerEffect(6, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), + false)); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private HowlpackPiper(final HowlpackPiper card) { diff --git a/Mage.Sets/src/mage/cards/h/HuatliPoetOfUnity.java b/Mage.Sets/src/mage/cards/h/HuatliPoetOfUnity.java index 83e01945e95..1d5c124a1b3 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliPoetOfUnity.java +++ b/Mage.Sets/src/mage/cards/h/HuatliPoetOfUnity.java @@ -1,20 +1,28 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.DinosaurVanillaToken; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -22,30 +30,74 @@ import java.util.UUID; /** * @author Susucr */ -public final class HuatliPoetOfUnity extends CardImpl { +public final class HuatliPoetOfUnity extends TransformingDoubleFacedCard { + + private static final FilterCard filterCard = new FilterCard("Dinosaur card"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.DINOSAUR, "Dinosaurs you control"); + + static { + filterCard.add(SubType.DINOSAUR.getPredicate()); + } public HuatliPoetOfUnity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.BARD}, "{2}{G}", + "Roar of the Fifth People", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "RGW" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.BARD); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.r.RoarOfTheFifthPeople.class; + // Huatli, Poet of Unity + this.getLeftHalfCard().setPT(2, 3); // When Huatli, Poet of Unity enters the battlefield, search your library for a basic land card, reveal it, put it into your hand, then shuffle. TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(target, true), false)); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(target, true), false)); // {3}{R/W}{R/W}: Exile Huatli, then return her to the battlefield transformed under her owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{3}{R/W}{R/W}") ); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Roar of the Fifth People + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard(), SagaChapter.CHAPTER_IV); + + // I -- Create two 3/3 green Dinosaur creature tokens. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new CreateTokenEffect(new DinosaurVanillaToken(), 2)); + + // II -- {this} gains "Creatures you control have '{T}: Add {R}, {G}, or {W}.'" + Ability gainedAbility = new SimpleStaticAbility(new GainAbilityControlledEffect( + new RedManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false + ).setText("Creatures you control have '{T}: Add {R}")); + gainedAbility.addEffect(new GainAbilityControlledEffect( + new GreenManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false + ).setText(", {G}")); + gainedAbility.addEffect(new GainAbilityControlledEffect( + new WhiteManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false + ).setText(", or {W}.'")); + + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, + new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield) + .setText("{this} gains \"Creatures you control have '{T}: Add {R}, {G}, or {W}.'\"")); + + // III -- Search your library for a Dinosaur card, reveal it, put it into your hand, then shuffle. + TargetCardInLibrary target2 = new TargetCardInLibrary(filterCard); + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, new SearchLibraryPutInHandEffect(target2, true)); + + // IV -- Dinosaurs you control gain double strike and trample until end of turn. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_IV, + new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filter + ).setText("Dinosaurs you control gain double strike"), + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, filter + ).setText("and trample until end of turn") + ); + + this.getRightHalfCard().addAbility(sagaAbility); } private HuatliPoetOfUnity(final HuatliPoetOfUnity card) { diff --git a/Mage.Sets/src/mage/cards/h/HumanTorch.java b/Mage.Sets/src/mage/cards/h/HumanTorch.java new file mode 100644 index 00000000000..27fef4bb874 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HumanTorch.java @@ -0,0 +1,140 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.DamagedBatchBySourceEvent; +import mage.game.events.GameEvent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HumanTorch extends CardImpl { + + public HumanTorch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // At the beginning of combat on your turn, if you've cast a noncreature spell this turn, Human Torch gains flying, double strike, and haste until end of turn. + Ability ability = new BeginningOfCombatTriggeredAbility( + new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("{this} gains flying") + ).withInterveningIf(CastNoncreatureSpellThisTurnCondition.instance); + ability.addEffect(new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText(", double strike")); + ability.addEffect(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText(", and haste until end of turn.")); + this.addAbility(ability.addHint(CastNoncreatureSpellThisTurnCondition.getHint())); + + // Whenever Human Torch attacks, you may pay {R}{G}{W}{U}. If you do, until end of turn, whenever he deals combat damage to an opponent, he deals that much damage to each other opponent. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new CreateDelayedTriggeredAbilityEffect(new HumanTorchTriggeredAbility()) + .setText("until end of turn, whenever he deals combat damage to an opponent, " + + "he deals that much damage to each other opponent"), + new ManaCostsImpl<>("{R}{G}{W}{U}") + ))); + } + + private HumanTorch(final HumanTorch card) { + super(card); + } + + @Override + public HumanTorch copy() { + return new HumanTorch(this); + } +} + +class HumanTorchTriggeredAbility extends DelayedTriggeredAbility { + + HumanTorchTriggeredAbility() { + super(new HumanTorchEffect(), Duration.EndOfTurn, false, false); + setTriggerPhrase("Whenever {this} deals combat damage to an opponent, "); + } + + private HumanTorchTriggeredAbility(final HumanTorchTriggeredAbility ability) { + super(ability); + } + + @Override + public HumanTorchTriggeredAbility copy() { + return new HumanTorchTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_BATCH_BY_SOURCE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getSourceId().equals(getSourceId()) + || !((DamagedBatchBySourceEvent) event).isCombatDamage() + || !game.getOpponents(getControllerId()).contains(event.getTargetId())) { + return false; + } + this.getEffects().setValue("playerId", event.getTargetId()); + this.getEffects().setValue("damage", event.getAmount()); + return true; + } +} + +class HumanTorchEffect extends OneShotEffect { + + HumanTorchEffect() { + super(Outcome.Benefit); + staticText = "he deals that much damage to each other opponent"; + } + + private HumanTorchEffect(final HumanTorchEffect effect) { + super(effect); + } + + @Override + public HumanTorchEffect copy() { + return new HumanTorchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID playerId = (UUID) getValue("playerId"); + int damage = (Integer) getValue("damage"); + if (damage < 1) { + return false; + } + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + if (!opponentId.equals(playerId)) { + Optional.ofNullable(opponentId) + .map(game::getPlayer) + .ifPresent(player -> player.damage(damage, source, game)); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HungryFlames.java b/Mage.Sets/src/mage/cards/h/HungryFlames.java index bd704cb8b14..d458bb6b8d2 100644 --- a/Mage.Sets/src/mage/cards/h/HungryFlames.java +++ b/Mage.Sets/src/mage/cards/h/HungryFlames.java @@ -1,14 +1,9 @@ package mage.cards.h; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; 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.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; @@ -22,10 +17,10 @@ public final class HungryFlames extends CardImpl { public HungryFlames(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); - // Hungry Flames deals 3 damage to target creature and 2 damage to target player. - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); - this.getSpellAbility().addEffect(new HungryFlamesEffect()); + // Hungry Flames deals 3 damage to target creature and 2 damage to target player or planeswalker. + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(2)); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(3, 2)); } private HungryFlames(final HungryFlames card) { @@ -37,37 +32,4 @@ public final class HungryFlames extends CardImpl { return new HungryFlames(this); } - private static class HungryFlamesEffect extends OneShotEffect { - - HungryFlamesEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 3 damage to target creature and 2 damage to target player or planeswalker"; - } - - private HungryFlamesEffect(final HungryFlamesEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getTargets().get(0).getFirstTarget()); - Player player = game.getPlayer(source.getTargets().get(1).getFirstTarget()); - - if (permanent != null) { - permanent.damage(3, source.getSourceId(), source, game, false, true); - } - - if (player != null) { - player.damage(2, source.getSourceId(), source, game); - } - - return true; - } - - @Override - public HungryFlamesEffect copy() { - return new HungryFlamesEffect(this); - } - } - } diff --git a/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java b/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java index 5994fd49068..ca890cf5573 100644 --- a/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java +++ b/Mage.Sets/src/mage/cards/h/HuntmasterOfTheFells.java @@ -1,43 +1,64 @@ package mage.cards.h; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.game.permanent.token.WolfToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponentOrPlaneswalker; +import mage.target.targetpointer.EachTargetPointer; +import java.util.Set; import java.util.UUID; /** * @author BetaSteward */ -public final class HuntmasterOfTheFells extends CardImpl { +public final class HuntmasterOfTheFells extends TransformingDoubleFacedCard { public HuntmasterOfTheFells(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{G}", + "Ravager of the Fells", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG" + ); - this.secondSideCardClazz = mage.cards.r.RavagerOfTheFells.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(2); + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(4, 4); // Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, create a 2/2 green Wolf creature token and you gain 2 life. Ability ability = new TransformsOrEntersTriggeredAbility(new CreateTokenEffect(new WolfToken()), false); ability.addEffect(new GainLifeEffect(2).concatBy("and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + + // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + Ability ravagerAbility = new TransformIntoSourceTriggeredAbility( + new RavagerOfTheFellsEffect(), false, true + ); + ravagerAbility.addTarget(new TargetOpponentOrPlaneswalker()); + ravagerAbility.addTarget(new RavagerOfTheFellsTarget()); + this.getRightHalfCard().addAbility(ravagerAbility); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private HuntmasterOfTheFells(final HuntmasterOfTheFells card) { @@ -49,3 +70,70 @@ public final class HuntmasterOfTheFells extends CardImpl { return new HuntmasterOfTheFells(this); } } + +class RavagerOfTheFellsEffect extends OneShotEffect { + + RavagerOfTheFellsEffect() { + super(Outcome.Damage); + this.setTargetPointer(new EachTargetPointer()); + staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " + + "to up to one target creature that player or that planeswalker's controller controls."; + } + + private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) { + super(effect); + } + + @Override + public RavagerOfTheFellsEffect copy() { + return new RavagerOfTheFellsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + game.damagePlayerOrPermanent( + targetId, 2, source.getSourceId(), source, + game, false, true + ); + } + return true; + } + +} + +class RavagerOfTheFellsTarget extends TargetPermanent { + + RavagerOfTheFellsTarget() { + super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) { + super(target); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + + Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget()); + if (needPlayer == null) { + // playable or not selected - use any + } else { + // filter by controller + possibleTargets.removeIf(id -> { + Permanent permanent = game.getPermanent(id); + return permanent == null + || permanent.getId().equals(source.getFirstTarget()) + || !permanent.isControlledBy(needPlayer.getId()); + }); + } + + return possibleTargets; + } + + @Override + public RavagerOfTheFellsTarget copy() { + return new RavagerOfTheFellsTarget(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HydaelynTheMothercrystal.java b/Mage.Sets/src/mage/cards/h/HydaelynTheMothercrystal.java deleted file mode 100644 index eee3edefdf4..00000000000 --- a/Mage.Sets/src/mage/cards/h/HydaelynTheMothercrystal.java +++ /dev/null @@ -1,89 +0,0 @@ -package mage.cards.h; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.game.Controllable; -import mage.game.Game; -import mage.target.TargetPermanent; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class HydaelynTheMothercrystal extends CardImpl { - - public HydaelynTheMothercrystal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setWhite(true); - - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - - // Blessing of Light -- At the beginning of combat on your turn, put a +1/+1 counter on another target creature you control. Until your next turn, it gains indestructible. If that creature is legendary, draw a card. - Ability ability = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - ability.addEffect(new GainAbilityTargetEffect( - IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn - ).setText("Until your next turn, it gains indestructible")); - ability.addEffect(new HydaelynTheMothercrystalEffect()); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); - this.addAbility(ability.withFlavorWord("Blessing of Light")); - } - - private HydaelynTheMothercrystal(final HydaelynTheMothercrystal card) { - super(card); - } - - @Override - public HydaelynTheMothercrystal copy() { - return new HydaelynTheMothercrystal(this); - } -} - -class HydaelynTheMothercrystalEffect extends OneShotEffect { - - HydaelynTheMothercrystalEffect() { - super(Outcome.Benefit); - staticText = "If that creature is legendary, draw a card"; - } - - private HydaelynTheMothercrystalEffect(final HydaelynTheMothercrystalEffect effect) { - super(effect); - } - - @Override - public HydaelynTheMothercrystalEffect copy() { - return new HydaelynTheMothercrystalEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return Optional.ofNullable(getTargetPointer().getFirst(game, source)) - .map(game::getPermanent) - .filter(permanent -> permanent.isLegendary(game)) - .isPresent() - && Optional - .ofNullable(source) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .filter(player -> player.drawCards(1, source, game) > 0) - .isPresent(); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IcebergTitan.java b/Mage.Sets/src/mage/cards/i/IcebergTitan.java deleted file mode 100644 index b5422ca61da..00000000000 --- a/Mage.Sets/src/mage/cards/i/IcebergTitan.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.MayTapOrUntapTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class IcebergTitan extends CardImpl { - - public IcebergTitan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.nightCard = true; - this.color.setBlue(true); - - // Whenever Iceberg Titan attacks, you may tap or untap target artifact or creature. - Ability ability = new AttacksTriggeredAbility(new MayTapOrUntapTargetEffect()); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); - this.addAbility(ability); - } - - private IcebergTitan(final IcebergTitan card) { - super(card); - } - - @Override - public IcebergTitan copy() { - return new IcebergTitan(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java index 8ab18e4d7ab..7f17695d748 100644 --- a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java +++ b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java @@ -1,12 +1,7 @@ - package mage.cards.i; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -21,6 +16,10 @@ import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * * @author L_J @@ -50,8 +49,9 @@ public final class IchneumonDruid extends CardImpl { class IchneumonDruidAbility extends TriggeredAbilityImpl { - public IchneumonDruidAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(4), false, "that player", true)); + IchneumonDruidAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(4).withTargetDescription("that player")); + setTriggerPhrase("Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, "); } private IchneumonDruidAbility(final IchneumonDruidAbility ability) { @@ -85,17 +85,13 @@ class IchneumonDruidAbility extends TriggeredAbilityImpl { return false; } - @Override - public String getRule() { - return "Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, {this} deals 4 damage to that player."; - } } class IchneumonDruidWatcher extends Watcher { private final Map playerInstantCount = new HashMap<>(); - public IchneumonDruidWatcher() { + IchneumonDruidWatcher() { super(WatcherScope.GAME); } diff --git a/Mage.Sets/src/mage/cards/i/IdolOfTheDeepKing.java b/Mage.Sets/src/mage/cards/i/IdolOfTheDeepKing.java index c76243b2c49..13abd8dc05f 100644 --- a/Mage.Sets/src/mage/cards/i/IdolOfTheDeepKing.java +++ b/Mage.Sets/src/mage/cards/i/IdolOfTheDeepKing.java @@ -1,13 +1,18 @@ package mage.cards.i; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAttachToTarget; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.CraftAbility; +import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.FlashAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -15,22 +20,36 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class IdolOfTheDeepKing extends CardImpl { +public final class IdolOfTheDeepKing extends TransformingDoubleFacedCard { public IdolOfTheDeepKing(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); - this.secondSideCardClazz = mage.cards.s.SovereignsMacuahuitl.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{R}", + "Sovereign's Macuahuitl", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "R" + ); + // Idol of the Deep King // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // When Idol of the Deep King enters the battlefield, it deals 2 damage to any target. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)); ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {2}{R} - this.addAbility(new CraftAbility("{2}{R}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{2}{R}")); + + // Sovereign's Macuahuitl + // When Sovereign's Macuahuitl enters the battlefield, attach it to target creature you control. + this.getRightHalfCard().addAbility(new EntersBattlefieldAttachToTarget()); + + // Equipped creature gets +2/+0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); + + // Equip {2} + this.getRightHalfCard().addAbility(new EquipAbility(2)); } private IdolOfTheDeepKing(final IdolOfTheDeepKing card) { diff --git a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java b/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java deleted file mode 100644 index 25f9b3ccc9f..00000000000 --- a/Mage.Sets/src/mage/cards/i/IfritWardenOfInferno.java +++ /dev/null @@ -1,72 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.common.SagaAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.effects.common.FightTargetSourceEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class IfritWardenOfInferno extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); - private static final Condition condition = new SourceHasCounterCondition(CounterType.LORE, 3); - - public IfritWardenOfInferno(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.DEMON); - this.power = new MageInt(9); - this.toughness = new MageInt(9); - this.nightCard = true; - this.color.setRed(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Lunge -- Ifrit fights up to one other target creature. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, ability -> { - ability.addEffect(new FightTargetSourceEffect()); - ability.addTarget(new TargetPermanent(0, 1, filter)); - ability.withFlavorWord("Lunge"); - }); - - // II, III -- Brimstone -- Add {R}{R}{R}{R}. If Ifrit has three or more lore counters on it, exile it, then return it to the battlefield - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new BasicManaEffect(Mana.RedMana(4))); - ability.addEffect(new ConditionalOneShotEffect( - new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD), condition, - "If {this} has three or more lore counters on it, exile it, " + - "then return it to the battlefield (front face up.)." - )); - ability.withFlavorWord("Brimstone"); - }); - this.addAbility(sagaAbility); - } - - private IfritWardenOfInferno(final IfritWardenOfInferno card) { - super(card); - } - - @Override - public IfritWardenOfInferno copy() { - return new IfritWardenOfInferno(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java b/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java index 08b861d29d1..2c789994b55 100644 --- a/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java +++ b/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java @@ -1,7 +1,7 @@ package mage.cards.i; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.DealtDamageAnyTriggeredAbility; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -9,11 +9,14 @@ import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SetTargetPointer; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -21,30 +24,48 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class IllTemperedLoner extends CardImpl { +public final class IllTemperedLoner extends TransformingDoubleFacedCard { public IllTemperedLoner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{R}", + "Howlpack Avenger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.h.HowlpackAvenger.class; + // Ill-Tempered Loner + this.getLeftHalfCard().setPT(3, 3); // Whenever Ill-Tempered Loner is dealt damage, it deals that much damage to any target. Ability ability = new DealtDamageToSourceTriggeredAbility( new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {1}{R}: Ill-Tempered Loner gets +2/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new BoostSourceEffect( 2, 0, Duration.EndOfTurn ), new ManaCostsImpl<>("{1}{R}"))); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Howlpack Avenger + this.getRightHalfCard().setPT(4, 4); + + // Whenever a permanent you control is dealt damage, Howlpack Avenger deals that much damage to any target. + Ability backAbility = new DealtDamageAnyTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH), + StaticFilters.FILTER_CONTROLLED_A_PERMANENT, SetTargetPointer.NONE, false); + backAbility.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(backAbility); + + // {1}{R}: Howlpack Avenger gets +2/+0 until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + 2, 0, Duration.EndOfTurn + ), new ManaCostsImpl<>("{1}{R}"))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private IllTemperedLoner(final IllTemperedLoner card) { diff --git a/Mage.Sets/src/mage/cards/i/ImmolationShaman.java b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java index 79fad9b9bdf..c78eb4351d7 100644 --- a/Mage.Sets/src/mage/cards/i/ImmolationShaman.java +++ b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -67,7 +66,7 @@ public final class ImmolationShaman extends CardImpl { class ImmolationShamanTriggeredAbility extends TriggeredAbilityImpl { ImmolationShamanTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(StaticValue.get(1), true, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player")); setTriggerPhrase("Whenever an opponent activates an ability of an artifact, creature, or land that isn't a mana ability, "); } diff --git a/Mage.Sets/src/mage/cards/i/ImmortalCoil.java b/Mage.Sets/src/mage/cards/i/ImmortalCoil.java index 60a13afacb5..f79ef75b715 100644 --- a/Mage.Sets/src/mage/cards/i/ImmortalCoil.java +++ b/Mage.Sets/src/mage/cards/i/ImmortalCoil.java @@ -6,6 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseGameSourceControllerEffect; @@ -17,10 +18,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; @@ -102,24 +100,14 @@ class ImmortalCoilPreventionEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - if (game.replaceEvent(new PreventDamageEvent( - event.getTargetId(), source.getSourceId(), source, source.getControllerId(), - event.getAmount(), ((DamageEvent) event).isCombatDamage() - ))) { - return false; - } - int damage = event.getAmount(); + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(Math.min(damage, player.getGraveyard().size()), StaticFilters.FILTER_CARD); + if (player != null && preventionEffectData.getPreventedDamage() > 0) { + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(Math.min(preventionEffectData.getPreventedDamage(), player.getGraveyard().size()), StaticFilters.FILTER_CARD); target.withNotTarget(true); player.choose(outcome, target, source, game); player.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent( - event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage - )); return false; } diff --git a/Mage.Sets/src/mage/cards/i/ImmovableRod.java b/Mage.Sets/src/mage/cards/i/ImmovableRod.java index 49cc0385d2d..4aeda0b0973 100644 --- a/Mage.Sets/src/mage/cards/i/ImmovableRod.java +++ b/Mage.Sets/src/mage/cards/i/ImmovableRod.java @@ -13,8 +13,7 @@ import mage.abilities.keyword.InspiredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -26,12 +25,6 @@ import java.util.UUID; */ public final class ImmovableRod extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public ImmovableRod(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{W}"); @@ -46,7 +39,7 @@ public final class ImmovableRod extends CardImpl { Ability ability = new SimpleActivatedAbility(new ImmovableRodAbilityEffect(), new ManaCostsImpl<>("{3}{W}")); ability.addEffect(new ImmovableRodAttackBlockTargetEffect()); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_PERMANENT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/ImperialMoth.java b/Mage.Sets/src/mage/cards/i/ImperialMoth.java deleted file mode 100644 index c3d40b92497..00000000000 --- a/Mage.Sets/src/mage/cards/i/ImperialMoth.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -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 ImperialMoth extends CardImpl { - - public ImperialMoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.INSECT); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private ImperialMoth(final ImperialMoth card) { - super(card); - } - - @Override - public ImperialMoth copy() { - return new ImperialMoth(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IncitedRabble.java b/Mage.Sets/src/mage/cards/i/IncitedRabble.java deleted file mode 100644 index 91003feeba6..00000000000 --- a/Mage.Sets/src/mage/cards/i/IncitedRabble.java +++ /dev/null @@ -1,48 +0,0 @@ - -package mage.cards.i; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.AttacksEachCombatStaticAbility; -import mage.abilities.common.SimpleActivatedAbility; -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.Duration; -import mage.constants.Zone; - -/** - * - * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) - */ -public final class IncitedRabble extends CardImpl { - - public IncitedRabble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Incited Rabble attacks each combat if able. - this.addAbility(new AttacksEachCombatStaticAbility()); - - // {2}: Incited Rabble gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{2}"))); - } - - private IncitedRabble(final IncitedRabble card) { - super(card); - } - - @Override - public IncitedRabble copy() { - return new IncitedRabble(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InfectiousCurse.java b/Mage.Sets/src/mage/cards/i/InfectiousCurse.java deleted file mode 100644 index 8df074292f5..00000000000 --- a/Mage.Sets/src/mage/cards/i/InfectiousCurse.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.cards.i; - -import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -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.game.stack.Spell; -import mage.target.TargetPlayer; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * @author halljared - */ -public final class InfectiousCurse extends CardImpl { - - public InfectiousCurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - this.subtype.add(SubType.AURA, SubType.CURSE); - this.color.setBlack(true); - - this.nightCard = true; - - // Enchant player - TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Damage)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Spells you cast that target enchanted player cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new InfectiousCurseCostReductionEffect())); - - // At the beginning of enchanted player's upkeep, that player loses 1 life and you gain 1 life. - Ability ability = new BeginningOfUpkeepTriggeredAbility( - TargetController.ENCHANTED, new LoseLifeTargetEffect(1).setText("that player loses 1 life"), - false - ); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private InfectiousCurse(final InfectiousCurse card) { - super(card); - } - - @Override - public InfectiousCurse copy() { - return new InfectiousCurse(this); - } -} - -class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl { - - InfectiousCurseCostReductionEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - this.staticText = "Spells you cast that target enchanted player cost {1} less to cast"; - } - - private InfectiousCurseCostReductionEffect(InfectiousCurseCostReductionEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, 1); - return true; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (!(abilityToModify instanceof SpellAbility)) { - return false; - } - - if (!source.isControlledBy(abilityToModify.getControllerId())) { - return false; - } - - Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment == null || enchantment.getAttachedTo() == null) { - return false; - } - - Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); - Set allTargets; - if (spell != null) { - // real cast - allTargets = CardUtil.getAllSelectedTargets(abilityToModify, game); - } else { - // playable - allTargets = CardUtil.getAllPossibleTargets(abilityToModify, game); - } - - // try to reduce all the time (if it possible to target) - return allTargets.stream().anyMatch(target -> Objects.equals(target, enchantment.getAttachedTo())); - } - - @Override - public InfectiousCurseCostReductionEffect copy() { - return new InfectiousCurseCostReductionEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InfernoElemental.java b/Mage.Sets/src/mage/cards/i/InfernoElemental.java index 1ba8734e94d..51de7e5c9ee 100644 --- a/Mage.Sets/src/mage/cards/i/InfernoElemental.java +++ b/Mage.Sets/src/mage/cards/i/InfernoElemental.java @@ -23,7 +23,8 @@ public final class InfernoElemental extends CardImpl { this.toughness = new MageInt(4); // Whenever Inferno Elemental blocks or becomes blocked by a creature, Inferno Elemental deals 3 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(3, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( + new DamageTargetEffect(3).withTargetDescription("that creature"))); } private InfernoElemental(final InfernoElemental card) { diff --git a/Mage.Sets/src/mage/cards/i/InfestationExpert.java b/Mage.Sets/src/mage/cards/i/InfestationExpert.java index b5bd768744e..726d58f041d 100644 --- a/Mage.Sets/src/mage/cards/i/InfestationExpert.java +++ b/Mage.Sets/src/mage/cards/i/InfestationExpert.java @@ -1,11 +1,11 @@ package mage.cards.i; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.InsectToken; @@ -15,24 +15,36 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InfestationExpert extends CardImpl { +public final class InfestationExpert extends TransformingDoubleFacedCard { public InfestationExpert(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}", + "Infested Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.i.InfestedWerewolf.class; + // Infestation Expert + this.getLeftHalfCard().setPT(3, 4); // Whenever Infestation Expert enters the battlefield or attacks, create a 1/1 green Insect creature token. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( new CreateTokenEffect(new InsectToken()) )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Infested Werewolf + this.getRightHalfCard().setPT(4, 5); + + // Whenever Infested Werewolf enters the battlefield or attacks, create two 1/1 green Insect creature token. + this.getRightHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new CreateTokenEffect(new InsectToken(), 2) + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private InfestationExpert(final InfestationExpert card) { diff --git a/Mage.Sets/src/mage/cards/i/InfestedWerewolf.java b/Mage.Sets/src/mage/cards/i/InfestedWerewolf.java deleted file mode 100644 index 96f815e0c32..00000000000 --- a/Mage.Sets/src/mage/cards/i/InfestedWerewolf.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.game.permanent.token.InsectToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class InfestedWerewolf extends CardImpl { - - public InfestedWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Infested Werewolf enters the battlefield or attacks, create two 1/1 green Insect creature token. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( - new CreateTokenEffect(new InsectToken(), 2) - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private InfestedWerewolf(final InfestedWerewolf card) { - super(card); - } - - @Override - public InfestedWerewolf copy() { - return new InfestedWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InheritedFiend.java b/Mage.Sets/src/mage/cards/i/InheritedFiend.java deleted file mode 100644 index 22343bddfb5..00000000000 --- a/Mage.Sets/src/mage/cards/i/InheritedFiend.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ExileTargetEffect; -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.StaticFilters; -import mage.target.common.TargetCardInGraveyard; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class InheritedFiend extends CardImpl { - - public InheritedFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.DEMON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // {2}{B}: Exile target creature card from a graveyard. Put a +1/+1 counter on Inherited Fiend. - Ability ability = new SimpleActivatedAbility(new ExileTargetEffect(), new ManaCostsImpl<>("{2}{B}")); - ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).concatBy(".")); - ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); - this.addAbility(ability); - } - - private InheritedFiend(final InheritedFiend card) { - super(card); - } - - @Override - public InheritedFiend copy() { - return new InheritedFiend(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InnocentTraveler.java b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java index 76e0b94422b..3987e659882 100644 --- a/Mage.Sets/src/mage/cards/i/InnocentTraveler.java +++ b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java @@ -1,13 +1,20 @@ package mage.cards.i; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.OpponentControlsPermanentCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; @@ -22,19 +29,36 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InnocentTraveler extends CardImpl { +public final class InnocentTraveler extends TransformingDoubleFacedCard { + + private static final FilterPermanent humanFilter = new FilterPermanent(SubType.HUMAN, "an opponent controls a Human"); + private static final Condition condition = new OpponentControlsPermanentCondition(humanFilter); + private static final Hint hint = new ConditionHint(condition, "An opponent controls a Human"); public InnocentTraveler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{2}{B}{B}", + "Malicious Invader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.m.MaliciousInvader.class; + // Innocent Traveler + this.getLeftHalfCard().setPT(1, 3); // At the beginning of your upkeep, any opponent may sacrifice a creature. If no one does, transform Innocent Traveler. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new InnocentTravelerEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new InnocentTravelerEffect())); + + // Malicious Invader + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Malicious Invader gets +2/+0 as long as an opponent controls a Human. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield), + condition, "{this} gets +2/+0 as long as an opponent controls a Human" + )).addHint(hint)); } private InnocentTraveler(final InnocentTraveler card) { diff --git a/Mage.Sets/src/mage/cards/i/InsectileAberration.java b/Mage.Sets/src/mage/cards/i/InsectileAberration.java deleted file mode 100644 index e946630432c..00000000000 --- a/Mage.Sets/src/mage/cards/i/InsectileAberration.java +++ /dev/null @@ -1,43 +0,0 @@ - -package mage.cards.i; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Alvin - */ -public final class InsectileAberration extends CardImpl { - - public InsectileAberration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.INSECT); - - this.color.setBlue(true); - - // this card is the second face of double-faced card Delver of Secrets - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private InsectileAberration(final InsectileAberration card) { - super(card); - } - - @Override - public InsectileAberration copy() { - return new InsectileAberration(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InsidiousMist.java b/Mage.Sets/src/mage/cards/i/InsidiousMist.java deleted file mode 100644 index 25546fc0589..00000000000 --- a/Mage.Sets/src/mage/cards/i/InsidiousMist.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.abilities.effects.common.combat.CantBlockSourceEffect; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TransformAbility; -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 fireshoes - */ -public final class InsidiousMist extends CardImpl { - - public InsidiousMist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(0); - this.toughness = new MageInt(1); - this.color.setBlue(true); - - this.nightCard = true; - - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - - // Insideous Mist can't block and can't be blocked. - Ability ability = new SimpleStaticAbility(new CantBlockSourceEffect(Duration.WhileOnBattlefield)); - ability.addEffect(new CantBeBlockedSourceEffect().setText("and can't be blocked")); - this.addAbility(ability); - - // Whenever Insideous Mist attacks and isn't blocked, you may pay {2}{B}. If you do, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new DoIfCostPaid(new TransformSourceEffect() - .setText("transform it"), new ManaCostsImpl<>("{2}{B}"), "Pay {2}{B} to transform?"))); - } - - private InsidiousMist(final InsidiousMist card) { - super(card); - } - - @Override - public InsidiousMist copy() { - return new InsidiousMist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InspiredInsurgent.java b/Mage.Sets/src/mage/cards/i/InspiredInsurgent.java new file mode 100644 index 00000000000..57c6b2f563c --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiredInsurgent.java @@ -0,0 +1,47 @@ +package mage.cards.i; + +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.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InspiredInsurgent extends CardImpl { + + public InspiredInsurgent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PEASANT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}, Sacrifice this creature: Destroy target artifact or enchantment. + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(1)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.addAbility(ability); + } + + private InspiredInsurgent(final InspiredInsurgent card) { + super(card); + } + + @Override + public InspiredInsurgent copy() { + return new InspiredInsurgent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InstigatorGang.java b/Mage.Sets/src/mage/cards/i/InstigatorGang.java index a88e96462f2..cfd163c2d97 100644 --- a/Mage.Sets/src/mage/cards/i/InstigatorGang.java +++ b/Mage.Sets/src/mage/cards/i/InstigatorGang.java @@ -1,12 +1,12 @@ package mage.cards.i; -import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -17,27 +17,41 @@ import java.util.UUID; /** * @author nantuko */ -public final class InstigatorGang extends CardImpl { +public final class InstigatorGang extends TransformingDoubleFacedCard { public InstigatorGang(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Wildblood Pack", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.w.WildbloodPack.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(3); + // Instigator Gang + this.getLeftHalfCard().setPT(2, 3); // Attacking creatures you control get +1/+0. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( 1, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_ATTACKING_CREATURES ))); // At the beginning of each upkeep, if no spells were cast last turn, transform Instigator Gang. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Wildblood Pack + this.getRightHalfCard().setPT(5, 5); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Attacking creatures you control get +3/+0. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 3, 0, Duration.WhileOnBattlefield, + StaticFilters.FILTER_ATTACKING_CREATURES, false + ))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Wildblood Pack. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private InstigatorGang(final InstigatorGang card) { diff --git a/Mage.Sets/src/mage/cards/i/InsultInjury.java b/Mage.Sets/src/mage/cards/i/InsultInjury.java index 9a9caea0e0c..a7cc880c8f6 100644 --- a/Mage.Sets/src/mage/cards/i/InsultInjury.java +++ b/Mage.Sets/src/mage/cards/i/InsultInjury.java @@ -1,8 +1,8 @@ package mage.cards.i; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect; import mage.abilities.keyword.AftermathAbility; import mage.cards.CardSetInfo; @@ -13,8 +13,6 @@ import mage.constants.Outcome; import mage.constants.SpellAbilityType; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import mage.util.CardUtil; @@ -39,9 +37,9 @@ public final class InsultInjury extends SplitCard { // Injury // Injury deals 2 damage to target creature and 2 damage to target player. getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); - getRightHalfCard().getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); - getRightHalfCard().getSpellAbility().addEffect(new InjuryEffect()); + getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + getRightHalfCard().getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(2)); + getRightHalfCard().getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 2)); } private InsultInjury(final InsultInjury card) { @@ -87,36 +85,3 @@ class InsultDoubleDamageEffect extends ReplacementEffectImpl { return false; } } - -class InjuryEffect extends OneShotEffect { - - InjuryEffect() { - super(Outcome.Damage); - this.staticText = "{this} deals 2 damage to target creature and 2 damage to target player or planeswalker"; - } - - private InjuryEffect(final InjuryEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getTargets().get(0).getFirstTarget()); - Player player = game.getPlayer(source.getTargets().get(1).getFirstTarget()); - - if (permanent != null) { - permanent.damage(2, source.getSourceId(), source, game, false, true); - } - - if (player != null) { - player.damage(2, source.getSourceId(), source, game); - } - - return true; - } - - @Override - public InjuryEffect copy() { - return new InjuryEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfAlara.java b/Mage.Sets/src/mage/cards/i/InvasionOfAlara.java index fd2160e9b63..cb0cb01ab51 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfAlara.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfAlara.java @@ -3,17 +3,27 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; import mage.cards.*; 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.TargetCard; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; import mage.target.common.TargetCardInExile; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanentAmount; +import mage.target.common.TargetPermanentAmount; +import mage.target.targetpointer.SecondTargetPointer; import mage.util.CardUtil; import java.util.UUID; @@ -21,21 +31,43 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfAlara extends CardImpl { +public final class InvasionOfAlara extends TransformingDoubleFacedCard { public InvasionOfAlara(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{W}{U}{B}{R}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{W}{U}{B}{R}{G}", + "Awaken the Maelstrom", + new CardType[]{CardType.SORCERY}, new SubType[]{}, "WUBRG" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(7); - this.secondSideCardClazz = mage.cards.a.AwakenTheMaelstrom.class; + // Invasion of Alara + this.getLeftHalfCard().setStartingDefense(7); - Ability ability = new SiegeAbility(); - ability.setRuleVisible(false); - this.addAbility(ability); + Ability siegeAbility = new SiegeAbility(); + siegeAbility.setRuleVisible(false); + this.getLeftHalfCard().addAbility(siegeAbility); // When Invasion of Alara enters the battlefield, exile cards from the top of your library until you exile two nonland cards with mana value 4 or less. You may cast one of those two cards without paying its mana cost. Put one of them into your hand. Then put the other cards exiled this way on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfAlaraEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfAlaraEffect())); + + // Awaken the Maelstrom + // Awaken the Maelstrom is all colors. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this} is all colors"))); + + // Target player draws two cards. + this.getRightHalfCard().getSpellAbility().addEffect(new DrawCardTargetEffect(2)); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer().withChooseHint("to draw two cards")); + + // You may put an artifact card from your hand onto the battlefield. + this.getRightHalfCard().getSpellAbility().addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_ARTIFACT_AN)); + + // Create a token that's a copy of a permanent you control. + // Distribute three +1/+1 counters among one, two, or three creatures you control. + this.getRightHalfCard().getSpellAbility().addEffect(new AwakenTheMaelstromEffect()); + + // Destroy target permanent an opponent controls. + this.getRightHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect().setTargetPointer(new SecondTargetPointer())); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT).withChooseHint("to destroy")); } private InvasionOfAlara(final InvasionOfAlara card) { @@ -101,3 +133,63 @@ class InvasionOfAlaraEffect extends OneShotEffect { return true; } } + +class AwakenTheMaelstromEffect extends OneShotEffect { + + AwakenTheMaelstromEffect() { + super(Outcome.Benefit); + staticText = "Create a token that's a copy of a permanent you control. " + + "Distribute three +1/+1 counters among one, two, or three creatures you control."; + } + + private AwakenTheMaelstromEffect(final AwakenTheMaelstromEffect effect) { + super(effect); + } + + @Override + public AwakenTheMaelstromEffect copy() { + return new AwakenTheMaelstromEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + makeToken(player, game, source); + game.processAction(); + distributeCounters(player, game, source); + return true; + } + + private void makeToken(Player player, Game game, Ability source) { + TargetPermanent target = new TargetControlledPermanent(); + target.withNotTarget(true); + target.withChooseHint("to copy"); + if (!target.canChoose(player.getId(), source, game)) { + return; + } + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + new CreateTokenCopyTargetEffect().setSavedPermanent(permanent).apply(game, source); + } + } + + private void distributeCounters(Player player, Game game, Ability source) { + if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game) < 1) { + return; + } + TargetPermanentAmount target = new TargetCreaturePermanentAmount(3, StaticFilters.FILTER_CONTROLLED_CREATURE); + target.withNotTarget(true); + target.withChooseHint("to distribute counters"); + target.chooseTarget(outcome, player.getId(), 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); + } + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfAmonkhet.java b/Mage.Sets/src/mage/cards/i/InvasionOfAmonkhet.java index 804e097c03a..9d15910563e 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfAmonkhet.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfAmonkhet.java @@ -1,33 +1,47 @@ package mage.cards.i; +import mage.MageObject; +import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.MillCardsEachPlayerEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.util.functions.CopyApplier; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfAmonkhet extends CardImpl { +public final class InvasionOfAmonkhet extends TransformingDoubleFacedCard { public InvasionOfAmonkhet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{U}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{1}{U}{B}", + "Lazotep Convert", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "UB" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.l.LazotepConvert.class; + // Invasion of Amonkhet + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Amonkhet enters the battlefield, each player mills three cards, then each opponent discards a card and you draw a card. Ability ability = new EntersBattlefieldTriggeredAbility( @@ -35,7 +49,13 @@ public final class InvasionOfAmonkhet extends CardImpl { ); ability.addEffect(new DiscardEachPlayerEffect(TargetController.OPPONENT).concatBy(", then")); ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and you")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Lazotep Convert + this.getRightHalfCard().setPT(4, 4); + + // You may have Lazotep Convert enter the battlefield as a copy of any creature card in a graveyard, except it's a 4/4 black Zombie in addition to its other types. + this.getRightHalfCard().addAbility(new EntersBattlefieldAbility(new LazotepConvertCopyEffect(), true)); } private InvasionOfAmonkhet(final InvasionOfAmonkhet card) { @@ -47,3 +67,59 @@ public final class InvasionOfAmonkhet extends CardImpl { return new InvasionOfAmonkhet(this); } } + +class LazotepConvertCopyEffect extends OneShotEffect { + + private static final CopyApplier applier = new CopyApplier() { + + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { + blueprint.removePTCDA(); + blueprint.getPower().setModifiedBaseValue(4); + blueprint.getToughness().setModifiedBaseValue(4); + blueprint.addSubType(SubType.ZOMBIE); + blueprint.getColor().addColor(ObjectColor.BLACK); + return true; + } + }; + + private static final FilterCard filter = new FilterCreatureCard("creature card in a graveyard"); + + public LazotepConvertCopyEffect() { + super(Outcome.Copy); + this.staticText = "as a copy of any creature card in a graveyard, " + + "except it's a 4/4 black Zombie in addition to its other colors and types"; + } + + private LazotepConvertCopyEffect(final LazotepConvertCopyEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetCardInGraveyard(0, 1, filter); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card copyFromCard = game.getCard(target.getFirstTarget()); + if (copyFromCard == null) { + return true; + } + Card modifiedCopy = copyFromCard.copy(); + //Appliers must be applied before CopyEffect, its applier setting is just for copies of copies + // TODO: research applier usage, why it here + applier.apply(game, modifiedCopy, source, source.getSourceId()); + game.addEffect(new CopyEffect( + Duration.Custom, modifiedCopy, source.getSourceId() + ).setApplier(applier), source); + return true; + } + + @Override + public LazotepConvertCopyEffect copy() { + return new LazotepConvertCopyEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfArcavios.java b/Mage.Sets/src/mage/cards/i/InvasionOfArcavios.java index 5e9b57214d3..7937789e674 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfArcavios.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfArcavios.java @@ -3,16 +3,22 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.WishEffect; import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterSpell; import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.predicate.card.CastFromZonePredicate; import mage.game.Game; +import mage.game.stack.Spell; import mage.players.Player; import java.util.UUID; @@ -20,20 +26,36 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfArcavios extends CardImpl { +public final class InvasionOfArcavios extends TransformingDoubleFacedCard { + + private static final FilterSpell filter + = new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"); + + static { + filter.add(new CastFromZonePredicate(Zone.HAND)); + } public InvasionOfArcavios(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{U}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{U}{U}", + "Invocation of the Founders", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "U" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(7); - this.secondSideCardClazz = mage.cards.i.InvocationOfTheFounders.class; + // Invasion of Arcavios + this.getLeftHalfCard().setStartingDefense(7); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Arcavios enters the battlefield, search your library, graveyard, and/or outside the game for an instant or sorcery card you own, reveal it, and put it into your hand. If you search your library this way, shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfArcaviosEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfArcaviosEffect())); + + // Invocation of the Founders + // Whenever you cast an instant or sorcery spell from your hand, you may copy that spell. You may choose new targets for the copy. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new InvocationOfTheFoundersEffect(), filter, true + )); } private InvasionOfArcavios(final InvasionOfArcavios card) { @@ -78,3 +100,30 @@ class InvasionOfArcaviosEffect extends OneShotEffect { ).apply(game, source); } } + +class InvocationOfTheFoundersEffect extends OneShotEffect { + + InvocationOfTheFoundersEffect() { + super(Outcome.Benefit); + staticText = "copy that spell. You may choose new targets for the copy"; + } + + private InvocationOfTheFoundersEffect(final InvocationOfTheFoundersEffect effect) { + super(effect); + } + + @Override + public InvocationOfTheFoundersEffect copy() { + return new InvocationOfTheFoundersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) getValue("spellCast"); + if (spell != null) { + spell.createCopyOnStack(game, source, source.getControllerId(), true); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfAzgol.java b/Mage.Sets/src/mage/cards/i/InvasionOfAzgol.java index 4e01acdf485..b7f157d7d19 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfAzgol.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfAzgol.java @@ -3,32 +3,45 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.SacrificeEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.cards.a.AshenReaper; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; import mage.target.TargetPlayer; +import mage.watchers.Watcher; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfAzgol extends CardImpl { +public final class InvasionOfAzgol extends TransformingDoubleFacedCard { public InvasionOfAzgol(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{B}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{B}{R}", + "Ashen Reaper", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE, SubType.ELEMENTAL}, "BR" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.a.AshenReaper.class; + // Invasion of Azgol + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Azgol enters the battlefield, target player sacrifices a creature or planeswalker and loses 1 life. Ability ability = new EntersBattlefieldTriggeredAbility(new SacrificeEffect( @@ -36,7 +49,23 @@ public final class InvasionOfAzgol extends CardImpl { )); ability.addEffect(new LoseLifeTargetEffect(1).setText("and loses 1 life")); ability.addTarget(new TargetPlayer()); - this.addAbility(ability, AshenReaper.makeWatcher()); + ability.addWatcher(new AshenReaperWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Ashen Reaper + this.getRightHalfCard().setPT(2, 1); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // At the beginning of your end step, put a +1/+1 counter on Ashen Reaper if a permanent was put into a graveyard from the battlefield this turn. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( + new ConditionalOneShotEffect( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + AshenReaperCondition.instance, "put a +1/+1 counter on {this} " + + "if a permanent was put into a graveyard from the battlefield this turn" + ) + )); } private InvasionOfAzgol(final InvasionOfAzgol card) { @@ -48,3 +77,27 @@ public final class InvasionOfAzgol extends CardImpl { return new InvasionOfAzgol(this); } } + +enum AshenReaperCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.getState().getWatcher(AshenReaperWatcher.class).conditionMet(); + } +} + +class AshenReaperWatcher extends Watcher { + + AshenReaperWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && ((ZoneChangeEvent) event).isDiesEvent()) { + condition = true; + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java b/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java index 717ac38bdc8..797ae3caef3 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfBelenon.java @@ -2,10 +2,13 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.game.permanent.token.KnightWhiteBlueToken; @@ -14,20 +17,27 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfBelenon extends CardImpl { +public final class InvasionOfBelenon extends TransformingDoubleFacedCard { public InvasionOfBelenon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}", + "Belenon War Anthem", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "W"); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.b.BelenonWarAnthem.class; + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Belenon enters the battlefield, create a 2/2 white and blue Knight creature token with vigilance. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken()))); + + // Belenon War Anthem + + // Creatures you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); + } private InvasionOfBelenon(final InvasionOfBelenon card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfDominaria.java b/Mage.Sets/src/mage/cards/i/InvasionOfDominaria.java index be85c55fce3..0a4a3619e4c 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfDominaria.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfDominaria.java @@ -5,8 +5,10 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,22 +17,34 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfDominaria extends CardImpl { +public final class InvasionOfDominaria extends TransformingDoubleFacedCard { public InvasionOfDominaria(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}", + "Serra Faithkeeper", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "W" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.s.SerraFaithkeeper.class; + // Invasion of Dominaria + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Dominaria enters the battlefield, you gain 4 life and draw a card. Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4)); ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Serra Faithkeeper + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); } private InvasionOfDominaria(final InvasionOfDominaria card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfEldraine.java b/Mage.Sets/src/mage/cards/i/InvasionOfEldraine.java index c42444b31d7..1a13b1e4fe7 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfEldraine.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfEldraine.java @@ -3,11 +3,15 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -15,22 +19,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfEldraine extends CardImpl { +public final class InvasionOfEldraine extends TransformingDoubleFacedCard { + + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); public InvasionOfEldraine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{B}", + "Prickle Faeries", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.FAERIE}, "B" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.p.PrickleFaeries.class; + // Invasion of Eldraine + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Eldraine enters the battlefield, target opponent discards two cards. Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2)); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Prickle Faeries + this.getRightHalfCard().setPT(2, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Prickle Faeries deals 2 damage to them. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, TargetController.OPPONENT, + new DamageTargetEffect(2).withTargetDescription("them"), false + ).withInterveningIf(condition)); } private InvasionOfEldraine(final InvasionOfEldraine card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfErgamon.java b/Mage.Sets/src/mage/cards/i/InvasionOfErgamon.java index 4a7e2e63e7f..2fdafc9c45e 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfErgamon.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfErgamon.java @@ -7,33 +7,60 @@ import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfErgamon extends CardImpl { +public final class InvasionOfErgamon extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("a land or battle card"); + + static { + filter.add(Predicates.or(CardType.LAND.getPredicate(), CardType.BATTLE.getPredicate())); + } public InvasionOfErgamon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{R}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{R}{G}", + "Truga Cliffcharger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.RHINO}, "RG" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.t.TrugaCliffcharger.class; + // Invasion of Ergamon + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Ergamon enters the battlefield, create a Treasure token. Then you may discard a card. If you do, draw a card. Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken())); ability.addEffect(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()).concatBy("Then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Truga Cliffcharger + this.getRightHalfCard().setPT(3, 4); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // When Truga Cliffcharger enters the battlefield, you may discard a card. If you do, search your library for a land or battle card, reveal it, put it into your hand, then shuffle. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( + new DoIfCostPaid(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filter), true + ), new DiscardCardCost()) + )); } private InvasionOfErgamon(final InvasionOfErgamon card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfFiora.java b/Mage.Sets/src/mage/cards/i/InvasionOfFiora.java index 339488dbb37..df1a598c3de 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfFiora.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfFiora.java @@ -2,53 +2,94 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.condition.Condition; import mage.abilities.effects.common.DestroyAllEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.cards.m.MarchesaResoluteMonarch; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.WatcherScope; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.target.TargetPermanent; +import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfFiora extends CardImpl { +public final class InvasionOfFiora extends TransformingDoubleFacedCard { - private static final FilterPermanent filter = new FilterCreaturePermanent("legendary creatures"); - private static final FilterPermanent filter2 = new FilterCreaturePermanent("nonlegendary creatures"); + private static final FilterPermanent filterLegend = new FilterCreaturePermanent("legendary creatures"); + private static final FilterPermanent filterNonLegend = new FilterCreaturePermanent("nonlegendary creatures"); static { - filter.add(SuperType.LEGENDARY.getPredicate()); - filter2.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + filterLegend.add(SuperType.LEGENDARY.getPredicate()); + filterNonLegend.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); } public InvasionOfFiora(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{4}{B}{B}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{4}{B}{B}", + "Marchesa, Resolute Monarch", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE}, "B" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.m.MarchesaResoluteMonarch.class; + // Invasion of Fiora + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Fiora enters the battlefield, choose one or both -- + // * Destroy all legendary creatures. - Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filter)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(filterLegend)); ability.getModes().setMinModes(1); ability.getModes().setMaxModes(2); // * Destroy all nonlegendary creatures. - ability.addMode(new Mode(new DestroyAllEffect(filter2))); - this.addAbility(ability, MarchesaResoluteMonarch.makeWatcher()); + ability.addMode(new Mode(new DestroyAllEffect(filterNonLegend))); + ability.addWatcher(new MarchesaResoluteMonarchWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Marchesa, Resolute Monarch + this.getRightHalfCard().setPT(3, 6); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Deathtouch + this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance()); + + // Whenever Marchesa, Resolute Monarch attacks, remove all counters from up to one target permanent. + Ability attackAbility = new AttacksTriggeredAbility(new RemoveAllCountersPermanentTargetEffect()); + attackAbility.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT)); + this.getRightHalfCard().addAbility(attackAbility); + + // At the beginning of your upkeep, if you haven't been dealt combat damage since your last turn, you draw a card and you lose 1 life. + Ability upkeepAbility = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1, true)) + .withInterveningIf(MarchesaResoluteMonarchCondition.instance); + upkeepAbility.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(upkeepAbility); } private InvasionOfFiora(final InvasionOfFiora card) { @@ -60,3 +101,49 @@ public final class InvasionOfFiora extends CardImpl { return new InvasionOfFiora(this); } } + +enum MarchesaResoluteMonarchCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return MarchesaResoluteMonarchWatcher.checkPlayer(game, source); + } + + @Override + public String toString() { + return "you haven't been dealt combat damage since your last turn"; + } +} + +class MarchesaResoluteMonarchWatcher extends Watcher { + + private final Set players = new HashSet<>(); + + MarchesaResoluteMonarchWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGED_PLAYER: + if (((DamagedEvent) event).isCombatDamage()) { + players.add(event.getTargetId()); + } + return; + case END_TURN_STEP_POST: + players.remove(game.getActivePlayerId()); + return; + + } + } + + static boolean checkPlayer(Game game, Ability source) { + return !game + .getState() + .getWatcher(MarchesaResoluteMonarchWatcher.class) + .players + .contains(source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java b/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java index d44cf14a51b..c507c2a5339 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfGobakhan.java @@ -5,18 +5,25 @@ import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.TargetCard; -import mage.target.common.TargetCardInHand; import mage.target.common.TargetOpponent; import mage.util.CardUtil; import mage.watchers.common.AttackedThisTurnWatcher; @@ -26,22 +33,42 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfGobakhan extends CardImpl { +public final class InvasionOfGobakhan extends TransformingDoubleFacedCard { public InvasionOfGobakhan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{1}{W}", + "Lightshield Array", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "W" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(3); - this.secondSideCardClazz = mage.cards.l.LightshieldArray.class; + // Invasion of Gobakhan + this.getLeftHalfCard().setStartingDefense(3); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Gobakhan enters the battlefield, look at target opponent's hand. You may exile a nonland card from it. For as long as that card remains exiled, its owner may play it. A spell cast this way costs {2} more to cast. Ability ability = new EntersBattlefieldTriggeredAbility(new InvasionOfGobakhanEffect()); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Lightshield Array + // At the beginning of your end step, put a +1/+1 counter on each creature that attacked this turn. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new LightshieldArrayEffect())); + + // Sacrifice Lightshield Array: Creatures you control gain hexproof and indestructible until end of turn. + Ability rightAbility = new SimpleActivatedAbility( + new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("creatures you control gain hexproof"), new SacrificeSourceCost() + ); + rightAbility.addEffect(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and indestructible until end of turn")); + this.getRightHalfCard().addAbility(rightAbility); } private InvasionOfGobakhan(final InvasionOfGobakhan card) { @@ -96,7 +123,7 @@ class InvasionOfGobakhanCastEffect extends AsThoughEffectImpl { private final MageObjectReference mor; - public InvasionOfGobakhanCastEffect(Card card, Game game) { + InvasionOfGobakhanCastEffect(Card card, Game game) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); this.mor = new MageObjectReference(card, game); } @@ -123,8 +150,7 @@ class InvasionOfGobakhanCastEffect extends AsThoughEffectImpl { discard(); return false; } - return mor.refersTo(CardUtil.getMainCardId(game, sourceId), game) - && card.isOwnedBy(affectedControllerId); + return mor.refersTo(CardUtil.getMainCardId(game, sourceId), game) && card.isOwnedBy(affectedControllerId); } } @@ -153,10 +179,10 @@ class InvasionOfGobakhanCostEffect extends CostModificationEffectImpl { if (!(abilityToModify instanceof SpellAbility)) { return false; } - if (game.inCheckPlayableState()) { // during playable check, the card is still in exile zone, the zcc is one less - UUID cardtoCheckId = CardUtil.getMainCardId(game, abilityToModify.getSourceId()); - return mor.getSourceId().equals(cardtoCheckId) - && mor.getZoneChangeCounter() == game.getState().getZoneChangeCounter(cardtoCheckId) + 1; + if (game.inCheckPlayableState()) { + UUID cardToCheckId = CardUtil.getMainCardId(game, abilityToModify.getSourceId()); + return mor.getSourceId().equals(cardToCheckId) + && mor.getZoneChangeCounter() == game.getState().getZoneChangeCounter(cardToCheckId) + 1; } else { return mor.refersTo(CardUtil.getMainCardId(game, abilityToModify.getSourceId()), game); } @@ -167,3 +193,34 @@ class InvasionOfGobakhanCostEffect extends CostModificationEffectImpl { return new InvasionOfGobakhanCostEffect(this); } } + +class LightshieldArrayEffect extends OneShotEffect { + + LightshieldArrayEffect() { + super(Outcome.Benefit); + staticText = "put a +1/+1 counter on each creature that attacked this turn"; + } + + private LightshieldArrayEffect(final LightshieldArrayEffect effect) { + super(effect); + } + + @Override + public LightshieldArrayEffect copy() { + return new LightshieldArrayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (MageObjectReference mor : game + .getState() + .getWatcher(AttackedThisTurnWatcher.class) + .getAttackedThisTurnCreatures()) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfIkoria.java b/Mage.Sets/src/mage/cards/i/InvasionOfIkoria.java index babbe2657ba..6f71ad803ce 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfIkoria.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfIkoria.java @@ -1,27 +1,32 @@ package mage.cards.i; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.search.SearchLibraryGraveyardPutOntoBattlefieldEffect; +import mage.abilities.keyword.ReachAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.Predicates; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfIkoria extends CardImpl { +public final class InvasionOfIkoria extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard("non-Human creature card with mana value X or less"); @@ -31,17 +36,29 @@ public final class InvasionOfIkoria extends CardImpl { } public InvasionOfIkoria(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{X}{G}{G}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{X}{G}{G}", + "Zilortha, Apex of Ikoria", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DINOSAUR}, "G" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(6); - this.secondSideCardClazz = mage.cards.z.ZilorthaApexOfIkoria.class; + // Invasion of Ikoria + this.getLeftHalfCard().setStartingDefense(6); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Ikoria enters the battlefield, search your library and/or graveyard for a non-Human creature card with mana value X or less and put it onto the battlefield. If you search your library this way, shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryGraveyardPutOntoBattlefieldEffect(filter))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryGraveyardPutOntoBattlefieldEffect(filter))); + + // Zilortha, Apex of Ikoria + this.getRightHalfCard().setPT(8, 8); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // For each non-Human creature you control, you may have that creature assign its combat damage as though it weren't blocked. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ZilorthaApexOfIkoriaEffect())); } private InvasionOfIkoria(final InvasionOfIkoria card) { @@ -59,7 +76,41 @@ enum InvasionOfIkoriaPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return input.getObject().getManaValue() - <= GetXValue.instance.calculate(game, input.getSource(), null); + return input.getObject().getManaValue() <= GetXValue.instance.calculate(game, input.getSource(), null); } -} \ No newline at end of file +} + +class ZilorthaApexOfIkoriaEffect extends AsThoughEffectImpl { + + ZilorthaApexOfIkoriaEffect() { + super(AsThoughEffectType.DAMAGE_NOT_BLOCKED, Duration.WhileOnBattlefield, Outcome.Damage); + this.staticText = "for each non-Human creature you control, you may have that " + + "creature assign its combat damage as though it weren't blocked"; + } + + private ZilorthaApexOfIkoriaEffect(ZilorthaApexOfIkoriaEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(sourceId); + return controller != null + && permanent != null + && permanent.isControlledBy(controller.getId()) + && !permanent.hasSubtype(SubType.HUMAN, game) + && controller.chooseUse(Outcome.Damage, "Have " + permanent.getLogName() + + " assign damage as though it weren't blocked?", source, game); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ZilorthaApexOfIkoriaEffect copy() { + return new ZilorthaApexOfIkoriaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfInnistrad.java b/Mage.Sets/src/mage/cards/i/InvasionOfInnistrad.java index 5505e05ceae..de4ac0e8e43 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfInnistrad.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfInnistrad.java @@ -3,12 +3,23 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.FlashAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -16,25 +27,37 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfInnistrad extends CardImpl { +public final class InvasionOfInnistrad extends TransformingDoubleFacedCard { public InvasionOfInnistrad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{B}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{B}{B}", + "Deluge of the Dead", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "B" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.d.DelugeOfTheDead.class; + // Invasion of Innistrad + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // When Invasion of Innistrad enters the battlefield, target creature an opponent controls gets -13/-13 until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-13, -13)); ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Deluge of the Dead + // When Deluge of the Dead enters the battlefield, create two 2/2 black Zombie creature tokens. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 2))); + + // {2}{B}: Exile target card from a graveyard. If it was a creature card, create a 2/2 black Zombie creature token. + Ability rightAbility = new SimpleActivatedAbility(new DelugeOfTheDeadEffect(), new ManaCostsImpl<>("{2}{B}")); + rightAbility.addTarget(new TargetCardInGraveyard()); + this.getRightHalfCard().addAbility(rightAbility); } private InvasionOfInnistrad(final InvasionOfInnistrad card) { @@ -46,3 +69,35 @@ public final class InvasionOfInnistrad extends CardImpl { return new InvasionOfInnistrad(this); } } + +class DelugeOfTheDeadEffect extends OneShotEffect { + + DelugeOfTheDeadEffect() { + super(Outcome.Benefit); + staticText = "exile target card from a graveyard. " + + "If it was a creature card, create a 2/2 black Zombie creature token"; + } + + private DelugeOfTheDeadEffect(final DelugeOfTheDeadEffect effect) { + super(effect); + } + + @Override + public DelugeOfTheDeadEffect copy() { + return new DelugeOfTheDeadEffect(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 (card.isCreature(game)) { + new ZombieToken().putOntoBattlefield(1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfIxalan.java b/Mage.Sets/src/mage/cards/i/InvasionOfIxalan.java index e9f5063c2d7..127c4ec565c 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfIxalan.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfIxalan.java @@ -2,10 +2,15 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.PutCards; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -15,23 +20,37 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfIxalan extends CardImpl { +public final class InvasionOfIxalan extends TransformingDoubleFacedCard { public InvasionOfIxalan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{1}{G}", + "Belligerent Regisaur", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DINOSAUR}, "G" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.b.BelligerentRegisaur.class; + // Invasion of Ixalan + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Ixalan enters the battlefield, look at the top five 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 a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( 5, 1, StaticFilters.FILTER_CARD_A_PERMANENT, PutCards.HAND, PutCards.BOTTOM_RANDOM ))); + + // Belligerent Regisaur + this.getRightHalfCard().setPT(4, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever you cast a spell, Belligerent Regisaur gains indestructible until end of turn. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ), false)); } private InvasionOfIxalan(final InvasionOfIxalan card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfKaladesh.java b/Mage.Sets/src/mage/cards/i/InvasionOfKaladesh.java index c4ed5fb6da3..47779abf9b8 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfKaladesh.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfKaladesh.java @@ -2,11 +2,18 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; import mage.game.permanent.token.ThopterColorlessToken; import java.util.UUID; @@ -14,20 +21,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfKaladesh extends CardImpl { +public final class InvasionOfKaladesh extends TransformingDoubleFacedCard { public InvasionOfKaladesh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{U}{R}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{U}{R}", + "Aetherwing, Golden-Scale Flagship", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "UR" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.a.AetherwingGoldenScaleFlagship.class; + // Invasion of Kaladesh + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Kaladesh enters the battlefield, create a 1/1 colorless Thopter artifact creature token with flying. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken()))); + + // Aetherwing, Golden-Scale Flagship + this.getRightHalfCard().setPT(0, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Aetherwing, Golden-Scale Flagship's power is equal to the number of artifacts you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, + new SetBasePowerSourceEffect(ArtifactYouControlCount.instance) + .setText("{this}'s power is equal to the number of artifacts you control") + )); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private InvasionOfKaladesh(final InvasionOfKaladesh card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfKaldheim.java b/Mage.Sets/src/mage/cards/i/InvasionOfKaldheim.java index b43d0aa8575..b8db517a142 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfKaldheim.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfKaldheim.java @@ -3,11 +3,19 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.cards.*; import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInHand; import mage.util.CardUtil; import java.util.UUID; @@ -15,20 +23,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfKaldheim extends CardImpl { +public final class InvasionOfKaldheim extends TransformingDoubleFacedCard { public InvasionOfKaldheim(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{R}", + "Pyre of the World Tree", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "R" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.p.PyreOfTheWorldTree.class; + // Invasion of Kaldheim + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Kaldheim enters the battlefield, exile all cards from your hand, then draw that many cards. Until the end of your next turn, you may play cards exiled this way. - this.addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfKaldheimEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfKaldheimEffect())); + + // Pyre of the World Tree + // Discard a land card: Pyre of the World Tree deals 2 damage to any target. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2), + new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_LAND_A)) + ); + ability.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(ability); + + // Whenever you discard a land card, exile the top card of your library. You may play that card this turn. + this.getRightHalfCard().addAbility(new DiscardCardControllerTriggeredAbility( + new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), + false, StaticFilters.FILTER_CARD_LAND_A + )); } private InvasionOfKaldheim(final InvasionOfKaldheim card) { @@ -45,8 +71,7 @@ class InvasionOfKaldheimEffect extends OneShotEffect { InvasionOfKaldheimEffect() { super(Outcome.Benefit); - staticText = "exile all cards from your hand, then draw that many cards. " + - "Until the end of your next turn, you may play cards exiled this way"; + staticText = "exile all cards from your hand, then draw that many cards. Until the end of your next turn, you may play cards exiled this way"; } private InvasionOfKaldheimEffect(final InvasionOfKaldheimEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfKamigawa.java b/Mage.Sets/src/mage/cards/i/InvasionOfKamigawa.java index fbbba61f607..8c4b1b8f77b 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfKamigawa.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfKamigawa.java @@ -1,12 +1,15 @@ package mage.cards.i; import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; @@ -18,23 +21,36 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfKamigawa extends CardImpl { +public final class InvasionOfKamigawa extends TransformingDoubleFacedCard { public InvasionOfKamigawa(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{U}", + "Rooftop Saboteurs", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MOONFOLK, SubType.NINJA}, "U" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.r.RooftopSaboteurs.class; + // Invasion of Kamigawa + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); // When Invasion of Kamigawa enters the battlefield, tap target artifact or creature an opponent controls and put a stun counter on it. - Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it")); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Rooftop Saboteurs + this.getRightHalfCard().setPT(2, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Rooftop Saboteurs deals combat damage to a player or battle, draw a card. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility( + new DrawCardSourceControllerEffect(1), false)); } private InvasionOfKamigawa(final InvasionOfKamigawa card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfKarsus.java b/Mage.Sets/src/mage/cards/i/InvasionOfKarsus.java index 3e0ad498ef9..2321710b2a7 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfKarsus.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfKarsus.java @@ -2,11 +2,16 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.DamageAllEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.keyword.WardAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; @@ -15,24 +20,35 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfKarsus extends CardImpl { +public final class InvasionOfKarsus extends TransformingDoubleFacedCard { - private static final FilterPermanent filter - = new FilterCreatureOrPlaneswalkerPermanent("creature and each planeswalker"); + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature and each planeswalker"); public InvasionOfKarsus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{R}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{R}{R}", + "Refraction Elemental", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL}, "R" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.r.RefractionElemental.class; + // Invasion of Karsus + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); - // When Invasion of Karsus enters the battlefield, it deals 3 damage to each creature and each planeswalker. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new DamageAllEffect(3, "it", filter) + // When this Siege enters, it deals 3 damage to each creature and each planeswalker. + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DamageAllEffect(3, "it", filter))); + + // Refraction Elemental + this.getRightHalfCard().setPT(4, 4); + + // Ward—Pay 2 life. + this.getRightHalfCard().addAbility(new WardAbility(new PayLifeCost(2), false)); + + // Whenever you cast a spell, Refraction Elemental deals 2 damage to each opponent. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new DamagePlayersEffect(2, TargetController.OPPONENT), false )); } diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfKylem.java b/Mage.Sets/src/mage/cards/i/InvasionOfKylem.java index 9fe9458f3a3..5670eb9d905 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfKylem.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfKylem.java @@ -3,14 +3,16 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.game.permanent.token.ValorsReachTagTeamToken; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -18,17 +20,19 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfKylem extends CardImpl { +public final class InvasionOfKylem extends TransformingDoubleFacedCard { public InvasionOfKylem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{R}{W}"); - - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.v.ValorsReachTagTeam.class; + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{R}{W}", + "Valor's Reach Tag Team", + new CardType[]{CardType.SORCERY}, new SubType[]{}, "RW" + ); + // Invasion of Kylem + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Kylem enters the battlefield, up to two target creatures each get +2/+0 and gain vigilance and haste until end of turn. Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0) @@ -38,7 +42,11 @@ public final class InvasionOfKylem extends CardImpl { ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) .setText("and haste until end of turn")); ability.addTarget(new TargetCreaturePermanent(0, 2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Valor's Reach Tag Team + // Create two 3/2 red and white Warrior creature tokens with "Whenever this creature and at least one other creature token attack, put a +1/+1 counter on this creature." + this.getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new ValorsReachTagTeamToken(), 2)); } private InvasionOfKylem(final InvasionOfKylem card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfLorwyn.java b/Mage.Sets/src/mage/cards/i/InvasionOfLorwyn.java index 128f73733a2..0da2e27ff23 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfLorwyn.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfLorwyn.java @@ -3,12 +3,16 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.hint.common.LandsYouControlHint; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterOpponentsCreaturePermanent; @@ -24,7 +28,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfLorwyn extends CardImpl { +public final class InvasionOfLorwyn extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent( "non-Elf creature an opponent controls with power X or less, where X is the number of lands you control" @@ -36,19 +40,30 @@ public final class InvasionOfLorwyn extends CardImpl { } public InvasionOfLorwyn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{4}{B}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{4}{B}{G}", + "Winnowing Forces", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELF, SubType.WARRIOR}, "BG" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.w.WinnowingForces.class; + // Invasion of Lorwyn + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Lorwyn enters the battlefield, destroy target non-Elf creature an opponent controls with power X or less, where X is the number of lands you control. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability.addHint(LandsYouControlHint.instance)); + this.getLeftHalfCard().addAbility(ability.addHint(LandsYouControlHint.instance)); + + // Winnowing Forces + this.getRightHalfCard().setPT(0, 0); + + // Winnowing Forces's power and toughness are each equal to the number of lands you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, new SetBasePowerToughnessSourceEffect(LandsYouControlCount.instance) + )); } private InvasionOfLorwyn(final InvasionOfLorwyn card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfMercadia.java b/Mage.Sets/src/mage/cards/i/InvasionOfMercadia.java index fc5c4e94077..19bb6ae49a0 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfMercadia.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfMercadia.java @@ -1,34 +1,64 @@ package mage.cards.i; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +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.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.Elemental11BlueRedToken; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfMercadia extends CardImpl { +public final class InvasionOfMercadia extends TransformingDoubleFacedCard { public InvasionOfMercadia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{1}{R}", + "Kyren Flamewright", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOBLIN, SubType.SPELLSHAPER}, "R" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.k.KyrenFlamewright.class; + // Invasion of Mercadia + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Mercadia enters the battlefield, you may discard a card. If you do, draw two cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(2), new DiscardCardCost()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(2), new DiscardCardCost()))); + + // Kyren Flamewright + this.getRightHalfCard().setPT(3, 3); + + // {2}{R}, {T}, Discard a card: Create two 1/1 blue and red Elemental creature tokens. Creatures you control get +1/+0 and gain haste until end of turn. + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new Elemental11BlueRedToken(), 2), new ManaCostsImpl<>("{2}{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addEffect(new BoostControlledEffect(1, 0, Duration.EndOfTurn) + .setText("creatures you control get +1/+0")); + ability.addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES + ).setText("and gain haste until end of turn")); + this.getRightHalfCard().addAbility(ability); } private InvasionOfMercadia(final InvasionOfMercadia card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfMoag.java b/Mage.Sets/src/mage/cards/i/InvasionOfMoag.java index 00f81345e85..8b396921c48 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfMoag.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfMoag.java @@ -1,36 +1,58 @@ package mage.cards.i; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.counter.AddCountersAllEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.WardAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfMoag extends CardImpl { +public final class InvasionOfMoag extends TransformingDoubleFacedCard { public InvasionOfMoag(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{G}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{G}{W}", + "Bloomwielder Dryads", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRYAD}, "GW" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.b.BloomwielderDryads.class; + // Invasion of Moag + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Moag enters the battlefield, put a +1/+1 counter on each creature you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect( CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE ))); + + // Bloomwielder Dryads + this.getRightHalfCard().setPT(3, 3); + + // Ward {2} + this.getRightHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + + // At the beginning of your end step, put a +1/+1 counter on target creature you control. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.getRightHalfCard().addAbility(ability); } private InvasionOfMoag(final InvasionOfMoag card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfMuraganda.java b/Mage.Sets/src/mage/cards/i/InvasionOfMuraganda.java index 6c312f0611b..3e6c7b295a3 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfMuraganda.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfMuraganda.java @@ -4,10 +4,14 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -19,27 +23,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfMuraganda extends CardImpl { +public final class InvasionOfMuraganda extends TransformingDoubleFacedCard { public InvasionOfMuraganda(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{4}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{4}{G}", + "Primordial Plasm", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.OOZE}, "G" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(6); - this.secondSideCardClazz = mage.cards.p.PrimordialPlasm.class; + // Invasion of Muraganda + this.getLeftHalfCard().setStartingDefense(6); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Muraganda enters the battlefield, put a +1/+1 counter on target creature you control. Then that creature fights up to one target creature you don't control. - Ability ability = new EntersBattlefieldTriggeredAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()) - ); - ability.addEffect(new FightTargetsEffect() - .setText("Then that creature fights up to one target creature you don't control")); + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addEffect(new FightTargetsEffect().setText("Then that creature fights up to one target creature you don't control")); ability.addTarget(new TargetControlledCreaturePermanent()); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Primordial Plasm + this.getRightHalfCard().setPT(4, 4); + + // At the beginning of combat on your turn, another target creature gets +2/+2 and loses all abilities until end of turn. + Ability combatAbility = new BeginningOfCombatTriggeredAbility( + new BoostTargetEffect(2, 2).setText("another target creature gets +2/+2") + ); + combatAbility.addEffect(new LoseAllAbilitiesTargetEffect(Duration.EndOfTurn) + .setText("and loses all abilities until end of turn")); + combatAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.getRightHalfCard().addAbility(combatAbility); } private InvasionOfMuraganda(final InvasionOfMuraganda card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfNewCapenna.java b/Mage.Sets/src/mage/cards/i/InvasionOfNewCapenna.java index a63d9651ffc..ce1de7da376 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfNewCapenna.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfNewCapenna.java @@ -1,17 +1,22 @@ package mage.cards.i; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.ExileTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.EquipAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import java.util.UUID; @@ -19,26 +24,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfNewCapenna extends CardImpl { +public final class InvasionOfNewCapenna extends TransformingDoubleFacedCard { public InvasionOfNewCapenna(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{W}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{W}{B}", + "Holy Frazzle-Cannon", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "WB" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.h.HolyFrazzleCannon.class; + // Invasion of New Capenna + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of New Capenna enters the battlefield, you may sacrifice an artifact or creature. When you do, exile target artifact or creature an opponent controls. - ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ExileTargetEffect(), false); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); - this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( - ability, + ReflexiveTriggeredAbility ref = new ReflexiveTriggeredAbility(new ExileTargetEffect(), false); + ref.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE)); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ref, new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE), - "Sacrifice and artifact or creature?" + "Sacrifice an artifact or creature?" ))); + + // Holy Frazzle-Cannon + // Whenever equipped creature attacks, put a +1/+1 counter on that creature and each other creature you control that shares a creature type with it. + this.getRightHalfCard().addAbility(new AttacksAttachedTriggeredAbility( + new HolyFrazzleCannonEffect(), AttachmentType.EQUIPMENT, + false, SetTargetPointer.PERMANENT + )); + + // Equip {1} + this.getRightHalfCard().addAbility(new EquipAbility(1, false)); } private InvasionOfNewCapenna(final InvasionOfNewCapenna card) { @@ -50,3 +68,37 @@ public final class InvasionOfNewCapenna extends CardImpl { return new InvasionOfNewCapenna(this); } } + +class HolyFrazzleCannonEffect extends OneShotEffect { + + HolyFrazzleCannonEffect() { + super(Outcome.Benefit); + staticText = "put a +1/+1 counter on that creature and " + + "each other creature you control that shares a creature type with it"; + } + + private HolyFrazzleCannonEffect(final HolyFrazzleCannonEffect effect) { + super(effect); + } + + @Override + public HolyFrazzleCannonEffect copy() { + return new HolyFrazzleCannonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + for (Permanent creature : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game + )) { + if (creature.equals(permanent) || permanent.shareCreatureTypes(game, creature)) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfNewPhyrexia.java b/Mage.Sets/src/mage/cards/i/InvasionOfNewPhyrexia.java index 314ce51080c..3d962924ae3 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfNewPhyrexia.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfNewPhyrexia.java @@ -1,34 +1,70 @@ package mage.cards.i; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.dynamicvalue.common.GetXValue; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.command.emblems.TeferiAkosaOfZhalfirEmblem; +import mage.game.permanent.Permanent; import mage.game.permanent.token.KnightWhiteBlueToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfNewPhyrexia extends CardImpl { +public final class InvasionOfNewPhyrexia extends TransformingDoubleFacedCard { public InvasionOfNewPhyrexia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{X}{W}{U}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{X}{W}{U}", + "Teferi Akosa of Zhalfir", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.TEFERI}, "WU" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(6); - this.secondSideCardClazz = mage.cards.t.TeferiAkosaOfZhalfir.class; + // Invasion of New Phyrexia + this.getLeftHalfCard().setStartingDefense(6); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of New Phyrexia enters the battlefield, create X 2/2 white and blue Knight creature tokens with vigilance. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken(), GetXValue.instance))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken(), GetXValue.instance))); + + // Teferi Akosa of Zhalfir + this.getRightHalfCard().setStartingLoyalty(4); + + // +1: Draw two cards. Then discard two cards unless you discard a creature card. + Ability ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 1); + ability.addEffect(new DoIfCostPaid( + null, new DiscardControllerEffect(2), + new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A)) + .setText("discard a creature card instead of discarding two cards") + ).setText("Then discard two cards unless you discard a creature card")); + this.getRightHalfCard().addAbility(ability); + + // -2: You get an emblem with "Knights you control get +1/+0 and have ward {1}." + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new TeferiAkosaOfZhalfirEmblem()), -2)); + + // -3: Tap any number of untapped creatures you control. When you do, shuffle target nonland permanent an opponent controls with mana value X or less into its owner's library, where X is the number of creatures tapped this way. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new TeferiAkosaOfZhalfirEffect(), -3)); } private InvasionOfNewPhyrexia(final InvasionOfNewPhyrexia card) { @@ -40,3 +76,50 @@ public final class InvasionOfNewPhyrexia extends CardImpl { return new InvasionOfNewPhyrexia(this); } } + +class TeferiAkosaOfZhalfirEffect extends OneShotEffect { + + TeferiAkosaOfZhalfirEffect() { + super(Outcome.Benefit); + staticText = "tap any number of untapped creatures you control. When you do, " + + "shuffle target nonland permanent an opponent controls with mana value X or less " + + "into its owner's library, where X is the number of creatures tapped this way"; + } + + private TeferiAkosaOfZhalfirEffect(final TeferiAkosaOfZhalfirEffect effect) { + super(effect); + } + + @Override + public TeferiAkosaOfZhalfirEffect copy() { + return new TeferiAkosaOfZhalfirEffect(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, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, true + ); + player.choose(Outcome.Tap, target, source, game); + int count = 0; + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null && permanent.tap(source, game)) { + count++; + } + } + FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls with mana value " + count + " or less"); + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, count + 1)); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ShuffleIntoLibraryTargetEffect() + .setText("shuffle target nonland permanent an opponent controls with mana value X or less " + + "into its owner's library, where X is the number of creatures tapped this way"), false); + ability.addTarget(new TargetPermanent(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java b/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java index beeee35bd4f..7845112de81 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfPyrulea.java @@ -3,11 +3,20 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.WardAbility; import mage.cards.*; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TransformedPredicate; import mage.game.Game; import mage.players.Player; @@ -16,20 +25,43 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfPyrulea extends CardImpl { +public final class InvasionOfPyrulea extends TransformingDoubleFacedCard { public InvasionOfPyrulea(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{G}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{G}{U}", + "Gargantuan Slabhorn", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BEAST}, "GU" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.g.GargantuanSlabhorn.class; + // Invasion of Pyrulea + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Pyrulea enters the battlefield, scry 3, then reveal the top card of your library. If it's a land or double-faced card, draw a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfPyruleaEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfPyruleaEffect())); + + // Gargantuan Slabhorn + this.getRightHalfCard().setPT(4, 4); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Ward {2} + this.getRightHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + + // Other transformed permanents you control have trample and ward {2}. + FilterPermanent filter = new FilterPermanent("transformed permanents"); + filter.add(TransformedPredicate.instance); + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + )); + ability.addEffect(new GainAbilityControlledEffect( + new WardAbility(new GenericManaCost(2)), Duration.WhileOnBattlefield, filter, true + ).setText("and ward {2}")); + this.getRightHalfCard().addAbility(ability); } private InvasionOfPyrulea(final InvasionOfPyrulea card) { @@ -67,7 +99,7 @@ class InvasionOfPyruleaEffect extends OneShotEffect { player.scry(3, source, game); Card card = player.getLibrary().getFromTop(game); player.revealCards(source, new CardsImpl(card), game); - if (card != null && (card.isLand(game) || card instanceof ModalDoubleFacedCard || card.getSecondCardFace() != null)) { + if (card != null && (card.isLand(game) || card instanceof DoubleFacedCard || card.getSecondCardFace() != null)) { player.drawCards(1, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfRavnica.java b/Mage.Sets/src/mage/cards/i/InvasionOfRavnica.java index 49b3a60b26f..26ffe207513 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfRavnica.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfRavnica.java @@ -1,15 +1,21 @@ package mage.cards.i; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.PutCards; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.Predicate; import mage.game.Game; @@ -21,7 +27,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfRavnica extends CardImpl { +public final class InvasionOfRavnica extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls that isn't exactly two colors"); @@ -30,20 +36,38 @@ public final class InvasionOfRavnica extends CardImpl { filter.add(InvasionOfRavnicaPredicate.instance); } + private static final FilterSpell spellFilter = new FilterSpell("a spell that's exactly two colors"); + private static final FilterCard cardFilter = new FilterCard("a card that's exactly two colors"); + + static { + spellFilter.add(GuildpactParagonPredicate.instance); + cardFilter.add(GuildpactParagonPredicate.instance); + } + public InvasionOfRavnica(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{5}"); - - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.g.GuildpactParagon.class; + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{5}", + "Guildpact Paragon", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.CONSTRUCT}, "" + ); + // Invasion of Ravnica + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Ravnica enters the battlefield, exile target nonland permanent an opponent controls that isn't exactly two colors. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Guildpact Paragon + this.getRightHalfCard().setPT(5, 5); + + // Whenever you cast a spell that's exactly two colors, look at the top six cards of your library. You may reveal a card that's exactly two colors from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new LookLibraryAndPickControllerEffect( + 6, 1, cardFilter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ), spellFilter, false)); } private InvasionOfRavnica(final InvasionOfRavnica card) { @@ -64,3 +88,12 @@ enum InvasionOfRavnicaPredicate implements Predicate { return input.getColor(game).getColorCount() != 2; } } + +enum GuildpactParagonPredicate implements Predicate { + instance; + + @Override + public boolean apply(MageObject input, Game game) { + return input.getColor(game).getColorCount() == 2; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java b/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java index 6096e876853..b8ef97f2586 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfRegatha.java @@ -1,30 +1,42 @@ package mage.cards.i; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; +import mage.abilities.keyword.ProwessAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterOpponent; import mage.filter.common.FilterBattlePermanent; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPermanentOrPlayer; -import mage.target.targetpointer.SecondTargetPointer; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfRegatha extends CardImpl { +public final class InvasionOfRegatha extends TransformingDoubleFacedCard { private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer( - "another target permanent or player", + "another target battle or opponent", new FilterBattlePermanent(), new FilterOpponent() ); @@ -33,30 +45,31 @@ public final class InvasionOfRegatha extends CardImpl { } public InvasionOfRegatha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{R}"); - - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.d.DisciplesOfTheInferno.class; + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{R}", + "Disciples of the Inferno", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "R" + ); + // Invasion of Regatha + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Regatha enters the battlefield, it deals 4 damage to another target battle or opponent and 1 damage to up to one target creature. - Ability ability = new EntersBattlefieldTriggeredAbility( - new DamageTargetEffect( - 4, true, - "another target battle or opponent", "it" + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetAndTargetEffect(4, 1)); + ability.addTarget(new TargetPermanentOrPlayer(filter).setTargetTag(1)); + ability.addTarget(new TargetCreaturePermanent(0, 1).setTargetTag(2)); + this.getLeftHalfCard().addAbility(ability); - ).setUseOnlyTargetPointer(true) - ); - ability.addTarget(new TargetPermanentOrPlayer(filter)); - ability.addEffect(new DamageTargetEffect(1) - .setUseOnlyTargetPointer(true) - .setTargetPointer(new SecondTargetPointer()) - .setText("and 1 damage to up to one target creature")); - ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); + // Disciples of the Inferno + this.getRightHalfCard().setPT(4, 4); + + // Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + + // If a noncreature source you control would deal damage to a creature, battle, or opponent, it deals that much damage plus 2 instead. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new DisciplesOfTheInfernoEffect())); } private InvasionOfRegatha(final InvasionOfRegatha card) { @@ -68,3 +81,61 @@ public final class InvasionOfRegatha extends CardImpl { return new InvasionOfRegatha(this); } } + +class DisciplesOfTheInfernoEffect extends ReplacementEffectImpl { + + DisciplesOfTheInfernoEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + this.staticText = "if a noncreature source you control would deal damage " + + "to a creature, battle, or opponent, it deals that much damage plus 2 instead"; + } + + private DisciplesOfTheInfernoEffect(final DisciplesOfTheInfernoEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.overflowInc(event.getAmount(), 2)); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PERMANENT: + case DAMAGE_PLAYER: + return true; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.hasOpponent(event.getTargetId(), game) + && Optional + .of(event.getTargetId()) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(permanent -> !permanent.isCreature(game) && !permanent.isBattle(game)) + .orElse(true)) { + return false; + } + MageObject sourceObject; + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (sourcePermanent == null) { + sourceObject = game.getObject(event.getSourceId()); + } else { + sourceObject = sourcePermanent; + } + return sourceObject != null + && !sourceObject.isCreature(game) + && event.getAmount() > 0; + } + + @Override + public DisciplesOfTheInfernoEffect copy() { + return new DisciplesOfTheInfernoEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfSegovia.java b/Mage.Sets/src/mage/cards/i/InvasionOfSegovia.java index fee4ad0287b..4b44e712ab9 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfSegovia.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfSegovia.java @@ -1,33 +1,65 @@ package mage.cards.i; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.permanent.token.Kraken11Token; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfSegovia extends CardImpl { +public final class InvasionOfSegovia extends TransformingDoubleFacedCard { + + private static final FilterNonlandCard filter = new FilterNonlandCard("noncreature spells you cast"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(new AbilityPredicate(ConvokeAbility.class))); + } public InvasionOfSegovia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{U}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{U}", + "Caetus, Sea Tyrant of Segovia", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SERPENT}, "U" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.c.CaetusSeaTyrantOfSegovia.class; + // Invasion of Segovia + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Segovia enters the battlefield, create two 1/1 blue Kraken creature tokens with trample. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Kraken11Token(), 2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Kraken11Token(), 2))); + + // Caetus, Sea Tyrant of Segovia + this.getRightHalfCard().setPT(3, 3); + + // Noncreature spells you cast have convoke. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter))); + + // At the beginning of your end step, untap up to four target creatures. + Ability ability = new BeginningOfEndStepTriggeredAbility(new UntapTargetEffect()); + ability.addTarget(new TargetCreaturePermanent(0, 4)); + this.getRightHalfCard().addAbility(ability); } private InvasionOfSegovia(final InvasionOfSegovia card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfShandalar.java b/Mage.Sets/src/mage/cards/i/InvasionOfShandalar.java index c1d9fa06b7a..b16c4ffcacb 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfShandalar.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfShandalar.java @@ -3,9 +3,11 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -16,22 +18,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfShandalar extends CardImpl { +public final class InvasionOfShandalar extends TransformingDoubleFacedCard { public InvasionOfShandalar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{G}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{G}{G}", + "Leyline Surge", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "G" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.l.LeylineSurge.class; + // Invasion of Shandalar + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Shandalar enters the battlefield, return up to three target permanent cards from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); ability.addTarget(new TargetCardInYourGraveyard(0, 3, StaticFilters.FILTER_CARD_PERMANENTS)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Leyline Surge + // At the beginning of your upkeep, you may put a permanent card from your hand onto the battlefield. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new PutCardFromHandOntoBattlefieldEffect( + StaticFilters.FILTER_CARD_A_PERMANENT + ))); } private InvasionOfShandalar(final InvasionOfShandalar card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfTarkir.java b/Mage.Sets/src/mage/cards/i/InvasionOfTarkir.java index c75e07bea0f..e13393a4eee 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfTarkir.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfTarkir.java @@ -1,25 +1,31 @@ package mage.cards.i; +import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterAnyTarget; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCardInHand; import mage.target.common.TargetPermanentOrPlayer; @@ -28,20 +34,37 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfTarkir extends CardImpl { +public final class InvasionOfTarkir extends TransformingDoubleFacedCard { public InvasionOfTarkir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{1}{R}", + "Defiant Thundermaw", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRAGON}, "R" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.d.DefiantThundermaw.class; + // Invasion of Tarkir + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Tarkir enters the battlefield, reveal any number of Dragon cards from your hand. When you do, Invasion of Tarkir deals X plus 2 damage to any other target, where X is the number of cards revealed this way. - this.addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfTarkirEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new InvasionOfTarkirEffect())); + + // Defiant Thundermaw + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever a Dragon you control attacks, it deals 2 damage to any target. + Ability ability = new AttacksCreatureYouControlTriggeredAbility(new DefiantThundermawEffect(), false, new FilterControlledCreaturePermanent(SubType.DRAGON)); + ability.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(ability); } private InvasionOfTarkir(final InvasionOfTarkir card) { @@ -66,8 +89,7 @@ class InvasionOfTarkirEffect extends OneShotEffect { InvasionOfTarkirEffect() { super(Outcome.Benefit); - staticText = "reveal any number of Dragon cards from your hand. When you do, " + - "{this} deals X plus 2 damage to any other target, where X is the number of cards revealed this way"; + staticText = "reveal any number of Dragon cards from your hand. When you do, {this} deals X plus 2 damage to any other target, where X is the number of cards revealed this way"; } private InvasionOfTarkirEffect(final InvasionOfTarkirEffect effect) { @@ -97,3 +119,33 @@ class InvasionOfTarkirEffect extends OneShotEffect { return true; } } + +class DefiantThundermawEffect extends OneShotEffect { + + DefiantThundermawEffect() { + super(Outcome.Benefit); + staticText = "it deals 2 damage to any target"; + } + + private DefiantThundermawEffect(final DefiantThundermawEffect effect) { + super(effect); + } + + @Override + public DefiantThundermawEffect copy() { + return new DefiantThundermawEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObjectReference mor = (MageObjectReference) getValue("attackerRef"); + if (mor == null) { + return false; + } + game.damagePlayerOrPermanent( + getTargetPointer().getFirst(game, source), 2, + mor.getSourceId(), source, game, false, true + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfTheros.java b/Mage.Sets/src/mage/cards/i/InvasionOfTheros.java index 91f8f74d716..44671b41d9f 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfTheros.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfTheros.java @@ -1,14 +1,32 @@ package mage.cards.i; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.cards.CardImpl; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledEnchantmentPermanent; import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -16,9 +34,10 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfTheros extends CardImpl { +public final class InvasionOfTheros extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCard("an Aura, God, or Demigod card"); + private static final FilterPermanent epharaFilter = new FilterControlledEnchantmentPermanent("another enchantment"); static { filter.add(Predicates.or( @@ -26,22 +45,55 @@ public final class InvasionOfTheros extends CardImpl { SubType.GOD.getPredicate(), SubType.DEMIGOD.getPredicate() )); + epharaFilter.add(AnotherPredicate.instance); } - public InvasionOfTheros(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}"); + static { + } - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.e.EpharaEverSheltering.class; + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + epharaFilter, ComparisonType.MORE_THAN, 2, true + ); + private static final Hint epharaHint = new ValueHint( + "Other enchantments you control", new PermanentsOnBattlefieldCount(epharaFilter) + ); + + public InvasionOfTheros(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}", + "Ephara, Ever-Sheltering", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.GOD}, "WU" + ); + + // Invasion of Theros + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Theros enters the battlefield, search your library for an Aura, God, or Demigod card, reveal it, put it into your hand, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) )); + + // Ephara, Ever-Sheltering + this.getRightHalfCard().setPT(4, 4); + + // Ephara, Ever-Sheltering has lifelink and indestructible as long as you control at least three other enchantments. + Ability staticAbility = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(LifelinkAbility.getInstance()), + condition, "{this} has lifelink" + )); + staticAbility.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance()), condition, + "and indestructible as long as you control at least three other enchantments" + )); + this.getRightHalfCard().addAbility(staticAbility.addHint(epharaHint)); + + // Whenever another enchantment you control enters, draw a card. + this.getRightHalfCard().addAbility(new EntersBattlefieldControlledTriggeredAbility( + new DrawCardSourceControllerEffect(1), epharaFilter + )); } private InvasionOfTheros(final InvasionOfTheros card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfTolvada.java b/Mage.Sets/src/mage/cards/i/InvasionOfTolvada.java index ed40650ae77..c618967a88c 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfTolvada.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfTolvada.java @@ -3,14 +3,24 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.WhiteBlackSpiritToken; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -18,7 +28,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfTolvada extends CardImpl { +public final class InvasionOfTolvada extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterPermanentCard("nonbattle permanent card from your graveyard"); @@ -26,20 +36,44 @@ public final class InvasionOfTolvada extends CardImpl { filter.add(Predicates.not(CardType.BATTLE.getPredicate())); } - public InvasionOfTolvada(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{W}{B}"); + private static final FilterCreaturePermanent tokenFilter = new FilterCreaturePermanent("creature tokens"); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.t.TheBrokenSky.class; + static { + tokenFilter.add(TokenPredicate.TRUE); + } + + public InvasionOfTolvada(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{W}{B}", + "The Broken Sky", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "WB" + ); + + // Invasion of Tolvada + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Tolvada enters the battlefield, return target nonbattle permanent card from your graveyard to the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); ability.addTarget(new TargetCardInYourGraveyard(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // The Broken Sky + // Creature tokens you control get +1/+0 and have lifelink. + Ability staticAbility = new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, tokenFilter + )); + staticAbility.addEffect(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, tokenFilter + ).setText("and have lifelink")); + this.getRightHalfCard().addAbility(staticAbility); + + // At the beginning of your end step, create a 1/1 white and black Spirit creature token with flying. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new WhiteBlackSpiritToken()) + )); } private InvasionOfTolvada(final InvasionOfTolvada card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfUlgrotha.java b/Mage.Sets/src/mage/cards/i/InvasionOfUlgrotha.java index f9c523ca427..2325d7277b8 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfUlgrotha.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfUlgrotha.java @@ -1,14 +1,20 @@ package mage.cards.i; import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -19,7 +25,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfUlgrotha extends CardImpl { +public final class InvasionOfUlgrotha extends TransformingDoubleFacedCard { private static final FilterPermanentOrPlayer filter = new FilterAnyTarget("any other target"); @@ -28,20 +34,37 @@ public final class InvasionOfUlgrotha extends CardImpl { } public InvasionOfUlgrotha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{4}{B}"); + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{4}{B}", + "Grandmother Ravi Sengir", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "B" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(5); - this.secondSideCardClazz = mage.cards.g.GrandmotherRaviSengir.class; + // Invasion of Ulgrotha + this.getLeftHalfCard().setStartingDefense(5); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Ulgrotha enters the battlefield, it deals 3 damage to any other target and you gain 3 life. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3, "it")); ability.addEffect(new GainLifeEffect(3).concatBy("and")); ability.addTarget(new TargetPermanentOrPlayer(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Grandmother Ravi Sengir + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever a creature an opponent controls dies, put a +1/+1 counter on Grandmother Ravi Sengir and you gain 1 life. + Ability diesAbility = new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE + ); + diesAbility.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(diesAbility); } private InvasionOfUlgrotha(final InvasionOfUlgrotha card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfVryn.java b/Mage.Sets/src/mage/cards/i/InvasionOfVryn.java index c4107e3b0fe..69ccb87ab25 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfVryn.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfVryn.java @@ -1,32 +1,60 @@ package mage.cards.i; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +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.CopyTargetStackObjectEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterSpell; +import mage.target.TargetSpell; import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfVryn extends CardImpl { +public final class InvasionOfVryn extends TransformingDoubleFacedCard { + + private static final FilterSpell filter = new FilterSpell("spell you control"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } public InvasionOfVryn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{U}", + "Overloaded Mage-Ring", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.o.OverloadedMageRing.class; + // Invasion of Vryn + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Vryn enters the battlefield, draw three cards, then discard a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 1))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 1))); + + // Overloaded Mage-Ring + // {1}, {T}, Sacrifice Overloaded Mage-Ring: Copy target spell you control. You may choose new targets for the copy. + Ability ability = new SimpleActivatedAbility( + new CopyTargetStackObjectEffect(false, false, true), new GenericManaCost(1) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.getRightHalfCard().addAbility(ability); } private InvasionOfVryn(final InvasionOfVryn card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfXerex.java b/Mage.Sets/src/mage/cards/i/InvasionOfXerex.java index fa5253a7bc9..d93de2b2ccc 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfXerex.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfXerex.java @@ -3,11 +3,16 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -15,22 +20,34 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfXerex extends CardImpl { +public final class InvasionOfXerex extends TransformingDoubleFacedCard { public InvasionOfXerex(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}{U}", + "Vertex Paladin", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL, SubType.KNIGHT}, "WU" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(4); - this.secondSideCardClazz = mage.cards.v.VertexPaladin.class; + // Invasion of Xerex + this.getLeftHalfCard().setStartingDefense(4); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); // When Invasion of Xerex enters the battlefield, return up to one target creature to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Vertex Paladin + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vertex Paladin's power and toughness are each equal to the number of creatures you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CreaturesYouControlCount.PLURAL))); } private InvasionOfXerex(final InvasionOfXerex card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionOfZendikar.java b/Mage.Sets/src/mage/cards/i/InvasionOfZendikar.java index 5f83a364830..f0b3955c634 100644 --- a/Mage.Sets/src/mage/cards/i/InvasionOfZendikar.java +++ b/Mage.Sets/src/mage/cards/i/InvasionOfZendikar.java @@ -2,10 +2,16 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SiegeAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInLibrary; @@ -15,22 +21,41 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InvasionOfZendikar extends CardImpl { +public final class InvasionOfZendikar extends TransformingDoubleFacedCard { public InvasionOfZendikar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{3}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{3}{G}", + "Awakened Skyclave", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL}, "G" + ); - this.subtype.add(SubType.SIEGE); - this.setStartingDefense(3); - this.secondSideCardClazz = mage.cards.a.AwakenedSkyclave.class; + // Invasion of Zendikar + this.getLeftHalfCard().setStartingDefense(3); // (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.) - this.addAbility(new SiegeAbility()); + this.getLeftHalfCard().addAbility(new SiegeAbility()); - // When Invasion of Zendikar enters the battlefield, search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + // When Invasion of Zendikar enters the battlefield, you may search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library. + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( 0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS ), true))); + + // Awakened Skyclave + this.getRightHalfCard().setPT(4, 4); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // As long as Awakened Skyclave is on the battlefield, it's a land in addition to its other types. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new AddCardTypeSourceEffect(Duration.WhileOnBattlefield, CardType.LAND) + .setText("as long as {this} is on the battlefield, it's a land in addition to its other types"))); + + // {T}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); } private InvasionOfZendikar(final InvasionOfZendikar card) { diff --git a/Mage.Sets/src/mage/cards/i/InvasionReinforcements.java b/Mage.Sets/src/mage/cards/i/InvasionReinforcements.java new file mode 100644 index 00000000000..905223017d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvasionReinforcements.java @@ -0,0 +1,44 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvasionReinforcements extends CardImpl { + + public InvasionReinforcements(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When this creature enters, create a 1/1 white Ally creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new AllyToken()))); + } + + private InvasionReinforcements(final InvasionReinforcements card) { + super(card); + } + + @Override + public InvasionReinforcements copy() { + return new InvasionReinforcements(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionSubmersible.java b/Mage.Sets/src/mage/cards/i/InvasionSubmersible.java new file mode 100644 index 00000000000..801328452b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvasionSubmersible.java @@ -0,0 +1,61 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.ExhaustAbility; +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.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvasionSubmersible extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public InvasionSubmersible(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // When this Vehicle enters, return up to one other target nonland permanent to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + + // Exhaust -- Waterbend {3}: This Vehicle becomes an artifact creature. Put three +1/+1 counters on it. + ability = new ExhaustAbility(new AddCardTypeSourceEffect(Duration.Custom, CardType.ARTIFACT, CardType.CREATURE), new WaterbendCost(3)); + ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)).setText("Put three +1/+1 counters on it")); + this.addAbility(ability); + } + + private InvasionSubmersible(final InvasionSubmersible card) { + super(card); + } + + @Override + public InvasionSubmersible copy() { + return new InvasionSubmersible(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasionTactics.java b/Mage.Sets/src/mage/cards/i/InvasionTactics.java new file mode 100644 index 00000000000..10bd57a35ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvasionTactics.java @@ -0,0 +1,46 @@ +package mage.cards.i; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvasionTactics extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ALLY, "Allies you control"); + + public InvasionTactics(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); + + // When this enchantment enters, creatures you control get +2/+2 until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new BoostControlledEffect(2, 2, Duration.EndOfTurn) + )); + + // Whenever one or more Allies you control deal combat damage to a player, draw a card. + this.addAbility(new OneOrMoreCombatDamagePlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter + )); + } + + private InvasionTactics(final InvasionTactics card) { + super(card); + } + + @Override + public InvasionTactics copy() { + return new InvasionTactics(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InventiveIteration.java b/Mage.Sets/src/mage/cards/i/InventiveIteration.java index 01b9469198f..95379ab1c8e 100644 --- a/Mage.Sets/src/mage/cards/i/InventiveIteration.java +++ b/Mage.Sets/src/mage/cards/i/InventiveIteration.java @@ -1,17 +1,22 @@ package mage.cards.i; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.StaticFilters; 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.common.TargetCardInYourGraveyard; @@ -23,31 +28,41 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class InventiveIteration extends CardImpl { +public final class InventiveIteration extends TransformingDoubleFacedCard { public InventiveIteration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.l.LivingBreakthrough.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{U}", + "Living Breakthrough", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.MOONFOLK}, "U" + ); + // Inventive Iteration // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Return up to one target creature or planeswalker to its owner's hand. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, new ReturnToHandTargetEffect(), new TargetCreatureOrPlaneswalker(0, 1) ); // II — Return an artifact card from your graveyard to your hand. If you can't, draw a card. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new InventiveIterationEffect()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new InventiveIterationEffect()); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Living Breakthrough + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever you cast a spell, your opponents can't cast spells with the same mana value as that spell until your next turn. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new LivingBreakthroughEffect(), false)); } private InventiveIteration(final InventiveIteration card) { @@ -102,3 +117,56 @@ class InventiveIterationEffect extends OneShotEffect { return true; } } + +class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl { + + private int manaValue = -1; + + LivingBreakthroughEffect() { + super(Duration.UntilYourNextTurn, Outcome.Benefit); + staticText = "your opponents can't cast spells with the same mana value as that spell until your next turn"; + } + + private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) { + super(effect); + this.manaValue = effect.manaValue; + } + + @Override + public LivingBreakthroughEffect copy() { + return new LivingBreakthroughEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + Spell spell = (Spell) getValue("spellCast"); + if (spell != null) { + this.manaValue = spell.getManaValue(); + } + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source); + if (mageObject != null) { + return "You can't cast spells with mana value " + manaValue + + " this turn (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL_LATE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; + } + Spell spell = game.getStack().getSpell(event.getTargetId()); + return spell != null && spell.getManaValue() == this.manaValue; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvertedIceberg.java b/Mage.Sets/src/mage/cards/i/InvertedIceberg.java index 0a4c7d497d3..28419263d17 100644 --- a/Mage.Sets/src/mage/cards/i/InvertedIceberg.java +++ b/Mage.Sets/src/mage/cards/i/InvertedIceberg.java @@ -1,32 +1,49 @@ package mage.cards.i; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.MayTapOrUntapTargetEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class InvertedIceberg extends CardImpl { +public final class InvertedIceberg extends TransformingDoubleFacedCard { public InvertedIceberg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); - this.secondSideCardClazz = mage.cards.i.IcebergTitan.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{U}", + "Iceberg Titan", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "U" + ); + // Inverted Iceberg // When Inverted Iceberg enters the battlefield, mill a card, then draw a card. Ability ability = new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(1)); ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy(", then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {4}{U}{U} - this.addAbility(new CraftAbility("{4}{U}{U}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{4}{U}{U}")); + + // Iceberg Titan + this.getRightHalfCard().setPT(6, 6); + + // Whenever Iceberg Titan attacks, you may tap or untap target artifact or creature. + Ability atkAbility = new AttacksTriggeredAbility(new MayTapOrUntapTargetEffect()); + atkAbility.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); + this.getRightHalfCard().addAbility(atkAbility); } private InvertedIceberg(final InvertedIceberg card) { diff --git a/Mage.Sets/src/mage/cards/i/InvisibleWoman.java b/Mage.Sets/src/mage/cards/i/InvisibleWoman.java new file mode 100644 index 00000000000..a2939873956 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvisibleWoman.java @@ -0,0 +1,63 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +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.WallColorlessReachToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvisibleWoman extends CardImpl { + + public InvisibleWoman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // At the beginning of combat on your turn, if you've cast a noncreature spell this turn, create a 0/3 colorless Wall creature token with defender and reach. + this.addAbility(new BeginningOfCombatTriggeredAbility(new CreateTokenEffect(new WallColorlessReachToken())) + .withInterveningIf(CastNoncreatureSpellThisTurnCondition.instance) + .addHint(CastNoncreatureSpellThisTurnCondition.getHint())); + + // Whenever you attack, you may pay {R}{G}{W}{U}. When you do, target creature gets +1/+0 until end of turn for each creature you control and can't be blocked this turn. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new BoostTargetEffect(CreaturesYouControlCount.SINGULAR, StaticValue.get(0)), false + ); + ability.addEffect(new CantBeBlockedTargetEffect().setText("and can't be blocked this turn")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new DoWhenCostPaid( + ability, new ManaCostsImpl<>("{R}{G}{W}{U}"), "Pay {R}{G}{W}{U}?" + ), 1)); + } + + private InvisibleWoman(final InvisibleWoman card) { + super(card); + } + + @Override + public InvisibleWoman copy() { + return new InvisibleWoman(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvocationOfTheFounders.java b/Mage.Sets/src/mage/cards/i/InvocationOfTheFounders.java deleted file mode 100644 index 798d94dea5f..00000000000 --- a/Mage.Sets/src/mage/cards/i/InvocationOfTheFounders.java +++ /dev/null @@ -1,78 +0,0 @@ -package mage.cards.i; - -import mage.abilities.Ability; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -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.FilterSpell; -import mage.filter.common.FilterInstantOrSorcerySpell; -import mage.filter.predicate.card.CastFromZonePredicate; -import mage.game.Game; -import mage.game.stack.Spell; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class InvocationOfTheFounders extends CardImpl { - - private static final FilterSpell filter - = new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"); - - static { - filter.add(new CastFromZonePredicate(Zone.HAND)); - } - - public InvocationOfTheFounders(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setBlue(true); - this.nightCard = true; - - // Whenever you cast an instant or sorcery spell from your hand, you may copy that spell. You may choose new targets for the copy. - this.addAbility(new SpellCastControllerTriggeredAbility( - new InvocationOfTheFoundersEffect(), filter, true - )); - } - - private InvocationOfTheFounders(final InvocationOfTheFounders card) { - super(card); - } - - @Override - public InvocationOfTheFounders copy() { - return new InvocationOfTheFounders(this); - } -} - -class InvocationOfTheFoundersEffect extends OneShotEffect { - - InvocationOfTheFoundersEffect() { - super(Outcome.Benefit); - staticText = "copy that spell. You may choose new targets for the copy"; - } - - private InvocationOfTheFoundersEffect(final InvocationOfTheFoundersEffect effect) { - super(effect); - } - - @Override - public InvocationOfTheFoundersEffect copy() { - return new InvocationOfTheFoundersEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Spell spell = (Spell) getValue("spellCast"); - if (spell != null) { - spell.createCopyOnStack(game, source, source.getControllerId(), true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java b/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java new file mode 100644 index 00000000000..90c7a212d26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrohDragonOfTheWest.java @@ -0,0 +1,61 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.MentorAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +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.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; + +import java.util.UUID; + +/** + * @author anonymous + */ +public final class IrohDragonOfTheWest extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(CounterAnyPredicate.instance); + } + + public IrohDragonOfTheWest(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Mentor + this.addAbility(new MentorAbility()); + + // At the beginning of combat on your turn, each creature you control with a counter on it gains firebending 2 until end of turn. + this.addAbility(new BeginningOfCombatTriggeredAbility(new GainAbilityControlledEffect( + new FirebendingAbility(2), Duration.EndOfTurn, filter + ).setText("each creature you control with a counter on it gains firebending 2 until end of turn"))); + } + + private IrohDragonOfTheWest(final IrohDragonOfTheWest card) { + super(card); + } + + @Override + public IrohDragonOfTheWest copy() { + return new IrohDragonOfTheWest(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java b/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java new file mode 100644 index 00000000000..7f07b6d407c --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrohGrandLotus.java @@ -0,0 +1,105 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrohGrandLotus extends CardImpl { + + public IrohGrandLotus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{U}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // During your turn, each non-Lesson instant and sorcery card in your graveyard has flashback. The flashback cost is equal to that card's mana cost. + this.addAbility(new SimpleStaticAbility(new IrohGrandLotusEffect(false))); + + // During your turn, each Lesson card in your graveyard has flashback {1}. + this.addAbility(new SimpleStaticAbility(new IrohGrandLotusEffect(true))); + } + + private IrohGrandLotus(final IrohGrandLotus card) { + super(card); + } + + @Override + public IrohGrandLotus copy() { + return new IrohGrandLotus(this); + } +} + +class IrohGrandLotusEffect extends ContinuousEffectImpl { + + private static final FilterCard filterNonLesson = new FilterInstantOrSorceryCard(); + private static final FilterCard filterLesson = new FilterCard(SubType.LESSON); + private final boolean isLesson; + + static { + filterNonLesson.add(Predicates.not(SubType.LESSON.getPredicate())); + } + + IrohGrandLotusEffect(boolean isLesson) { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.isLesson = isLesson; + if (isLesson) { + staticText = "during your turn, each Lesson card in your graveyard has flashback {1}"; + } else { + staticText = "during your turn, each non-Lesson instant and sorcery card in your graveyard has flashback. " + + "The flashback cost is equal to that card's mana cost"; + } + } + + private IrohGrandLotusEffect(final IrohGrandLotusEffect effect) { + super(effect); + this.isLesson = effect.isLesson; + } + + @Override + public IrohGrandLotusEffect copy() { + return new IrohGrandLotusEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!game.isActivePlayer(source.getControllerId())) { + return false; + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + for (Card card : player.getGraveyard().getCards(isLesson ? filterLesson : filterNonLesson, game)) { + Ability ability = new FlashbackAbility(card, isLesson ? new GenericManaCost(1) : card.getManaCost()); + ability.setSourceId(card.getId()); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java b/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java new file mode 100644 index 00000000000..d153c830fa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrohTeaMaster.java @@ -0,0 +1,148 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.AllyToken; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.EachTargetPointer; +import mage.target.targetpointer.FixedTarget; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrohTeaMaster extends CardImpl { + + public IrohTeaMaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Iroh enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // At the beginning of combat on your turn, you may have target opponent gain control of target permanent you control. When you do, create a 1/1 white Ally creature token. Put a +1/+1 counter on that token for each permanent you own that your opponents control. + Ability ability = new BeginningOfCombatTriggeredAbility(new IrohTeaMasterControlEffect(), true); + ability.addTarget(new TargetOpponent()); + ability.addTarget(new TargetControlledPermanent()); + this.addAbility(ability.addHint(IrohTeaMasterTokenEffect.getHint())); + } + + private IrohTeaMaster(final IrohTeaMaster card) { + super(card); + } + + @Override + public IrohTeaMaster copy() { + return new IrohTeaMaster(this); + } +} + +class IrohTeaMasterControlEffect extends OneShotEffect { + + IrohTeaMasterControlEffect() { + super(Outcome.Benefit); + staticText = "have target opponent gain control of target permanent you control. " + + "When you do, create a 1/1 white Ally creature token. " + + "Put a +1/+1 counter on that token for each permanent you own that your opponents control"; + this.setTargetPointer(new EachTargetPointer()); + } + + private IrohTeaMasterControlEffect(final IrohTeaMasterControlEffect effect) { + super(effect); + } + + @Override + public IrohTeaMasterControlEffect copy() { + return new IrohTeaMasterControlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanent(getTargetPointer().getTargets(game, source).get(0)); + if (player == null || permanent == null) { + return false; + } + game.addEffect(new GainControlTargetEffect(Duration.Custom, true, player.getId()) + .setTargetPointer(new FixedTarget(permanent, game)), source); + game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility(new IrohTeaMasterTokenEffect(), false), source); + return true; + } +} + +class IrohTeaMasterTokenEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + private static final Hint hint = new ValueHint( + "Permanents you own that your opponents control", new PermanentsOnBattlefieldCount(filter) + ); + + public static Hint getHint() { + return hint; + } + + IrohTeaMasterTokenEffect() { + super(Outcome.Benefit); + staticText = "create a 1/1 white Ally creature token. Put a +1/+1 counter " + + "on that token for each permanent you own that your opponents control"; + } + + private IrohTeaMasterTokenEffect(final IrohTeaMasterTokenEffect effect) { + super(effect); + } + + @Override + public IrohTeaMasterTokenEffect copy() { + return new IrohTeaMasterTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new AllyToken(); + token.putOntoBattlefield(1, game, source); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); + if (count < 1) { + return true; + } + for (UUID tokenId : token.getLastAddedTokenIds()) { + Optional.ofNullable(tokenId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.addCounters(CounterType.P1P1.createInstance(count), source, game)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java b/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java new file mode 100644 index 00000000000..4af1b269bab --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IrohsDemonstration.java @@ -0,0 +1,42 @@ +package mage.cards.i; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageAllEffect; +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.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IrohsDemonstration extends CardImpl { + + public IrohsDemonstration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + this.subtype.add(SubType.LESSON); + + // Choose one -- + // * Iroh's Demonstration deals 1 damage to each creature your opponents control. + this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) + .setText("{this} deals 1 damage to each creature your opponents control")); + + // * Iroh's Demonstration deals 4 damage to target creature. + this.getSpellAbility().addMode(new Mode(new DamageTargetEffect(4)).addTarget(new TargetCreaturePermanent())); + } + + private IrohsDemonstration(final IrohsDemonstration card) { + super(card); + } + + @Override + public IrohsDemonstration copy() { + return new IrohsDemonstration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java b/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java index 1b97e9734d0..98205ee3a57 100644 --- a/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java +++ b/Mage.Sets/src/mage/cards/i/IronSpiderStarkUpgrade.java @@ -29,11 +29,14 @@ import java.util.UUID; public final class IronSpiderStarkUpgrade extends CardImpl { private static final FilterPermanent filter - = new FilterControlledPermanent("creature and/or Vehicle you control"); + = new FilterControlledPermanent("artifact creature and/or Vehicle you control"); static { filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), + Predicates.and( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + ), SubType.VEHICLE.getPredicate() )); } @@ -59,7 +62,7 @@ public final class IronSpiderStarkUpgrade extends CardImpl { Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); ability.addCost(new RemoveCounterCost(new TargetPermanent( 1, 2, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT - ), CounterType.P1P1, 2).setText("remove two +1/+1 counters from among creatures you control")); + ), CounterType.P1P1, 2).setText("remove two +1/+1 counters from among artifacts you control")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/Ironfang.java b/Mage.Sets/src/mage/cards/i/Ironfang.java deleted file mode 100644 index 500ad43411f..00000000000 --- a/Mage.Sets/src/mage/cards/i/Ironfang.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class Ironfang extends CardImpl { - - public Ironfang(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(1); - - this.addAbility(FirstStrikeAbility.getInstance()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ironfang. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private Ironfang(final Ironfang card) { - super(card); - } - - @Override - public Ironfang copy() { - return new Ironfang(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java index 6cbc709eefb..554e8c77c3b 100644 --- a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java +++ b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java @@ -28,7 +28,7 @@ public final class IshiIshiAkkiCrackshot extends CardImpl { // Whenever an opponent casts a Spirit or Arcane spell, Ishi-Ishi, Akki Crackshot deals 2 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java b/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java deleted file mode 100644 index 54e585d92c9..00000000000 --- a/Mage.Sets/src/mage/cards/i/IsiluCarrierOfTwilight.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.i; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.PersistAbility; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class IsiluCarrierOfTwilight extends CardImpl { - - public IsiluCarrierOfTwilight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELEMENTAL); - this.subtype.add(SubType.GOD); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Each other nontoken creature you control has persist. - this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( - new PersistAbility(), Duration.WhileControlled, - StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, true - ).setText("each other nontoken creature you control has persist"))); - - // At the beginning of your first main phase, you may pay {W}. If you do, transform Isilu. - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{W}")) - )); - } - - private IsiluCarrierOfTwilight(final IsiluCarrierOfTwilight card) { - super(card); - } - - @Override - public IsiluCarrierOfTwilight copy() { - return new IsiluCarrierOfTwilight(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/ItThatRidesAsOne.java b/Mage.Sets/src/mage/cards/i/ItThatRidesAsOne.java deleted file mode 100644 index c5105c31ff9..00000000000 --- a/Mage.Sets/src/mage/cards/i/ItThatRidesAsOne.java +++ /dev/null @@ -1,46 +0,0 @@ - -package mage.cards.i; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FirstStrikeAbility; -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; - -/** - * - * @author fireshoes - */ -public final class ItThatRidesAsOne extends CardImpl { - - public ItThatRidesAsOne(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - // Trample - this.addAbility(TrampleAbility.getInstance()); - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private ItThatRidesAsOne(final ItThatRidesAsOne card) { - super(card); - } - - @Override - public ItThatRidesAsOne copy() { - return new ItThatRidesAsOne(this); - } -} diff --git a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java b/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java deleted file mode 100644 index 30411803120..00000000000 --- a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.i; - -import mage.Mana; -import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; -import mage.abilities.hint.common.CreaturesYouControlHint; -import mage.abilities.mana.DynamicManaAbility; -import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; - -import java.util.UUID; - -/** - * @author JRHerlehy - */ -public final class ItlimocCradleOfTheSun extends CardImpl { - - public ItlimocCradleOfTheSun(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - // (Transforms from Growing Rites of Itlimoc.)/ - this.nightCard = true; - - // {T}: Add {G}. - this.addAbility(new GreenManaAbility()); - - // {T}: Add {G} for each creature you control. - this.addAbility(new DynamicManaAbility( - Mana.GreenMana(1), CreaturesYouControlCount.SINGULAR - ).addHint(CreaturesYouControlHint.instance)); - } - - private ItlimocCradleOfTheSun(final ItlimocCradleOfTheSun card) { - super(card); - } - - @Override - public ItlimocCradleOfTheSun copy() { - return new ItlimocCradleOfTheSun(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java b/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java deleted file mode 100644 index 66e1b793d62..00000000000 --- a/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.j; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.MayCastTargetCardEffect; -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.SubType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; -import mage.game.command.emblems.JaceTelepathUnboundEmblem; -import mage.target.common.TargetCardInYourGraveyard; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class JaceTelepathUnbound extends CardImpl { - - public JaceTelepathUnbound(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.JACE); - - this.color.setBlue(true); - this.nightCard = true; - - this.setStartingLoyalty(5); - - // +1: Up to one target creature gets -2/-0 until your next turn. - Ability ability = new LoyaltyAbility(new BoostTargetEffect( - -2, 0, Duration.UntilYourNextTurn - ).setText("Up to one target creature gets -2/-0 until your next turn"), 1); - ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); - - // -3: You may cast target instant or sorcery card from your graveyard this turn. If that card would be put into your graveyard this turn, exile it instead. - ability = new LoyaltyAbility(new MayCastTargetCardEffect(Duration.EndOfTurn, true), -3); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); - this.addAbility(ability); - - // −9: You get an emblem with "Whenever you cast a spell, target opponent mills five cards." - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new JaceTelepathUnboundEmblem()), -9)); - } - - private JaceTelepathUnbound(final JaceTelepathUnbound card) { - super(card); - } - - @Override - public JaceTelepathUnbound copy() { - return new JaceTelepathUnbound(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaceVrynsProdigy.java b/Mage.Sets/src/mage/cards/j/JaceVrynsProdigy.java index 7c8eb721011..3e2d9e76ffa 100644 --- a/Mage.Sets/src/mage/cards/j/JaceVrynsProdigy.java +++ b/Mage.Sets/src/mage/cards/j/JaceVrynsProdigy.java @@ -1,7 +1,7 @@ package mage.cards.j; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; @@ -9,39 +9,61 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.MayCastTargetCardEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.command.emblems.JaceTelepathUnboundEmblem; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author LevelX2 */ -public final class JaceVrynsProdigy extends CardImpl { +public final class JaceVrynsProdigy extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(5); public JaceVrynsProdigy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(0); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{U}", + "Jace, Telepath Unbound", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.JACE}, "U"); - this.secondSideCardClazz = mage.cards.j.JaceTelepathUnbound.class; + // Jace, Vryn's Prodigy (front) + this.getLeftHalfCard().setPT(0, 2); - // {T}: Draw a card, then discard a card. If there are five or more cards in your graveyard, exile Jace, Vryn's Prodigy, then return him to the battefield transformed under his owner's control. - this.addAbility(new TransformAbility()); + // {T}: Draw a card, then discard a card. If there are five or more cards in your graveyard, exile Jace, Vryn's Prodigy, then return him to the battlefield transformed under his owner's control. Ability ability = new SimpleActivatedAbility( new DrawDiscardControllerEffect(1, 1), new TapSourceCost() ); ability.addEffect(new ConditionalOneShotEffect( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), condition )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Jace, Telepath Unbound (back) + this.getRightHalfCard().setStartingLoyalty(5); + + // +1: Up to one target creature gets -2/-0 until your next turn. + Ability pwAbility = new LoyaltyAbility(new BoostTargetEffect( + -2, 0, Duration.UntilYourNextTurn + ).setText("Up to one target creature gets -2/-0 until your next turn"), 1); + pwAbility.addTarget(new TargetCreaturePermanent(0, 1)); + this.getRightHalfCard().addAbility(pwAbility); + + // -3: You may cast target instant or sorcery card from your graveyard this turn. If that card would be put into your graveyard this turn, exile it instead. + pwAbility = new LoyaltyAbility(new MayCastTargetCardEffect(Duration.EndOfTurn, true), -3); + pwAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(pwAbility); + + // −9: You get an emblem with "Whenever you cast a spell, target opponent mills five cards." (emblem class unchanged) + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new JaceTelepathUnboundEmblem()), -9)); } private JaceVrynsProdigy(final JaceVrynsProdigy card) { diff --git a/Mage.Sets/src/mage/cards/j/JackalFamiliar.java b/Mage.Sets/src/mage/cards/j/JackalFamiliar.java index cac871879e3..ed46e360569 100644 --- a/Mage.Sets/src/mage/cards/j/JackalFamiliar.java +++ b/Mage.Sets/src/mage/cards/j/JackalFamiliar.java @@ -1,30 +1,29 @@ package mage.cards.j; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author magenoxx_at_gmail.com */ public final class JackalFamiliar extends CardImpl { public JackalFamiliar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.JACKAL); this.power = new MageInt(2); this.toughness = new MageInt(2); // Jackal Familiar can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private JackalFamiliar(final JackalFamiliar card) { diff --git a/Mage.Sets/src/mage/cards/j/JacobHaukenInspector.java b/Mage.Sets/src/mage/cards/j/JacobHaukenInspector.java index c71aedd5f2c..de6b8119722 100644 --- a/Mage.Sets/src/mage/cards/j/JacobHaukenInspector.java +++ b/Mage.Sets/src/mage/cards/j/JacobHaukenInspector.java @@ -1,49 +1,65 @@ package mage.cards.j; -import java.util.UUID; -import mage.MageInt; +import mage.MageIdentifier; import mage.MageObject; +import mage.MageObjectReference; 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.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.constants.*; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.game.ExileZone; import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; 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 weirddan455 */ -public final class JacobHaukenInspector extends CardImpl { +public final class JacobHaukenInspector extends TransformingDoubleFacedCard { public JacobHaukenInspector(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ADVISOR}, "{1}{U}", + "Hauken's Insight", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "U"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ADVISOR); - this.power = new MageInt(0); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.h.HaukensInsight.class; + // Jacob Hauken, Inspector + this.getLeftHalfCard().setPT(0, 2); // {T}: Draw a card, then exile a card from your hand face down. You may look at that card for as long as it remains exiled. You may pay {4}{U}{U}. If you do, transform Jacob Hauken, Inspector. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new JacobHaukenInspectorExileEffect(), new TapSourceCost()); ability.addEffect(new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U}{U}"))); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Hauken's Insight + + // At the beginning of your upkeep, exile the top card of your library face down. You may look at that card for as long as it remains exiled. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new HaukensInsightExileEffect())); + + // Once during each of your turns, you may play a land or cast a spell from among the cards exiled with this permanent without paying its mana cost. + Ability playAbility = new SimpleStaticAbility(new HaukensInsightPlayEffect()) + .setIdentifier(MageIdentifier.HaukensInsightWatcher); + playAbility.addWatcher(new HaukensInsightWatcher()); + this.getRightHalfCard().addAbility(playAbility); } private JacobHaukenInspector(final JacobHaukenInspector card) { @@ -135,3 +151,146 @@ class JacobHaukenInspectorLookEffect extends AsThoughEffectImpl { && objectId.equals(cardId); } } + +class HaukensInsightExileEffect extends OneShotEffect { + + HaukensInsightExileEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of your library face down. You may look at that card for as long as it remains exiled"; + } + + private HaukensInsightExileEffect(final HaukensInsightExileEffect effect) { + super(effect); + } + + @Override + public HaukensInsightExileEffect copy() { + return new HaukensInsightExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC()); + MageObject sourceObject = source.getSourceObject(game); + String exileName = sourceObject == null ? null : sourceObject.getIdName(); + card.setFaceDown(true, game); + controller.moveCardsToExile(card, source, game, false, exileId, exileName); + if (game.getState().getZone(card.getId()) == Zone.EXILED) { + card.setFaceDown(true, game); + HaukensInsightLookEffect effect = new HaukensInsightLookEffect(controller.getId()); + effect.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(effect, source); + return true; + } + } + } + return false; + } +} + +class HaukensInsightLookEffect extends AsThoughEffectImpl { + + private final UUID authorizedPlayerId; + + public HaukensInsightLookEffect(UUID authorizedPlayerId) { + super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); + this.authorizedPlayerId = authorizedPlayerId; + } + + private HaukensInsightLookEffect(final HaukensInsightLookEffect effect) { + super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; + } + + @Override + public HaukensInsightLookEffect copy() { + return new HaukensInsightLookEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + UUID cardId = getTargetPointer().getFirst(game, source); + if (cardId == null) { + this.discard(); // card is no longer in the origin zone, effect can be discarded + } + return affectedControllerId.equals(authorizedPlayerId) + && objectId.equals(cardId); + } +} + +class HaukensInsightPlayEffect extends AsThoughEffectImpl { + + HaukensInsightPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PlayForFree); + staticText = "Once during each of your turns, you may play a land or cast a spell from among the cards exiled with this permanent without paying its mana cost"; + } + + private HaukensInsightPlayEffect(final HaukensInsightPlayEffect effect) { + super(effect); + } + + @Override + public HaukensInsightPlayEffect copy() { + return new HaukensInsightPlayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (affectedControllerId.equals(source.getControllerId()) && game.isActivePlayer(source.getControllerId())) { + Player controller = game.getPlayer(source.getControllerId()); + HaukensInsightWatcher watcher = game.getState().getWatcher(HaukensInsightWatcher.class); + Permanent sourceObject = game.getPermanent(source.getSourceId()); + if (controller != null && watcher != null && sourceObject != null && !watcher.isAbilityUsed(new MageObjectReference(sourceObject, game))) { + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId())); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null && exileZone.contains(CardUtil.getMainCardId(game, objectId))) { + allowCardToPlayWithoutMana(objectId, source, affectedControllerId, MageIdentifier.HaukensInsightWatcher, game); + return true; + } + } + } + return false; + } +} + +class HaukensInsightWatcher extends Watcher { + + private final Set usedFrom = new HashSet<>(); + + public HaukensInsightWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST || event.getType() == GameEvent.EventType.LAND_PLAYED) { + if (event.hasApprovingIdentifier(MageIdentifier.HaukensInsightWatcher)) { + usedFrom.add(event.getApprovingObject().getApprovingMageObjectReference()); + } + } + } + + @Override + public void reset() { + super.reset(); + usedFrom.clear(); + } + + public boolean isAbilityUsed(MageObjectReference mor) { + return usedFrom.contains(mor); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JadeSeedstones.java b/Mage.Sets/src/mage/cards/j/JadeSeedstones.java index 55cde970259..0d67cd34d26 100644 --- a/Mage.Sets/src/mage/cards/j/JadeSeedstones.java +++ b/Mage.Sets/src/mage/cards/j/JadeSeedstones.java @@ -1,36 +1,55 @@ package mage.cards.j; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.DistributeCountersEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; import mage.target.common.TargetCreaturePermanentAmount; +import mage.util.CardUtil; import java.util.UUID; /** * @author TheElk801 */ -public final class JadeSeedstones extends CardImpl { +public final class JadeSeedstones extends TransformingDoubleFacedCard { public JadeSeedstones(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{G}"); - this.secondSideCardClazz = mage.cards.j.JadeheartAttendant.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}{G}", + "Jadeheart Attendant", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "G"); + + // Jade Seedstones // When Jade Seedstones enters the battlefield, distribute three +1/+1 counters among one, two, or three target creatures you control. Ability ability = new EntersBattlefieldTriggeredAbility(new DistributeCountersEffect()); ability.addTarget(new TargetCreaturePermanentAmount(3, StaticFilters.FILTER_CONTROLLED_CREATURES)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with creature {5}{G}{G} - this.addAbility(new CraftAbility( - "{5}{G}{G}", "creature", "another creature you control " + - "or a creature card in your graveyard", CardType.CREATURE.getPredicate()) + this.getLeftHalfCard().addAbility(new CraftAbility( + "{5}{G}{G}", "creature", "another creature you control or a creature card in your graveyard", CardType.CREATURE.getPredicate()) ); + + // Jadeheart Attendant + this.getRightHalfCard().setPT(7, 7); + + // When Jadeheart Attendant enters the battlefield, you gain life equal to the mana value of the exiled card used to craft it. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(JadeheartAttendantValue.instance) + .setText("you gain life equal to the mana value of the exiled card used to craft it"))); } private JadeSeedstones(final JadeSeedstones card) { @@ -42,3 +61,42 @@ public final class JadeSeedstones extends CardImpl { return new JadeSeedstones(this); } } + +enum JadeheartAttendantValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Card sourceCard = game.getCard(sourceAbility.getSourceId()); + if (sourceCard == null) { + return 0; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId(game, + sourceCard.getMainCard().getMainCard().getId(), + sourceCard.getMainCard().getZoneChangeCounter(game) - 1)); + return exileZone != null + ? exileZone + .getCards(game) + .stream() + .mapToInt(MageObject::getManaValue) + .sum() + : 0; + } + + @Override + public JadeheartAttendantValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JadeheartAttendant.java b/Mage.Sets/src/mage/cards/j/JadeheartAttendant.java deleted file mode 100644 index fddf0981f84..00000000000 --- a/Mage.Sets/src/mage/cards/j/JadeheartAttendant.java +++ /dev/null @@ -1,80 +0,0 @@ -package mage.cards.j; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.GainLifeEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.game.ExileZone; -import mage.game.Game; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class JadeheartAttendant extends CardImpl { - - public JadeheartAttendant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.nightCard = true; - this.color.setGreen(true); - - // When Jadeheart Attendant enters the battlefield, you gain life equal to the mana value of the exiled card used to craft it. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(JadeheartAttendantValue.instance) - .setText("you gain life equal to the mana value of the exiled card used to craft it"))); - } - - private JadeheartAttendant(final JadeheartAttendant card) { - super(card); - } - - @Override - public JadeheartAttendant copy() { - return new JadeheartAttendant(this); - } -} - -enum JadeheartAttendantValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId(game, sourceAbility, -2)); - return exileZone != null - ? exileZone - .getCards(game) - .stream() - .mapToInt(MageObject::getManaValue) - .sum() - : 0; - } - - @Override - public JadeheartAttendantValue copy() { - return this; - } - - @Override - public String getMessage() { - return ""; - } - - @Override - public String toString() { - return "1"; - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaggedLightning.java b/Mage.Sets/src/mage/cards/j/JaggedLightning.java index 0da793f9011..5a818c25a6a 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedLightning.java +++ b/Mage.Sets/src/mage/cards/j/JaggedLightning.java @@ -17,7 +17,7 @@ public final class JaggedLightning extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); // Jagged Lightning deals 3 damage to each of two target creatures. - this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "each of two target creatures")); + this.getSpellAbility().addEffect(new DamageTargetEffect(3).withTargetDescription("each of two target creatures")); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2)); } diff --git a/Mage.Sets/src/mage/cards/j/JaredCarthalionTrueHeir.java b/Mage.Sets/src/mage/cards/j/JaredCarthalionTrueHeir.java index f23761bd6e5..83c076a64c7 100644 --- a/Mage.Sets/src/mage/cards/j/JaredCarthalionTrueHeir.java +++ b/Mage.Sets/src/mage/cards/j/JaredCarthalionTrueHeir.java @@ -34,8 +34,7 @@ public final class JaredCarthalionTrueHeir extends CardImpl { this.toughness = new MageInt(3); // When Jared Carthalion, True Heir enters the battlefield, target opponent becomes the monarch. You can't become the monarch this turn. - Ability ability = new EntersBattlefieldTriggeredAbility(new BecomesMonarchTargetEffect() - .setText("target opponent becomes the monarch")); + Ability ability = new EntersBattlefieldTriggeredAbility(new BecomesMonarchTargetEffect()); ability.addEffect(new JaredCarthalionTrueHeirMonarchEffect()); ability.addTarget(new TargetOpponent()); ability.addHint(MonarchHint.instance); diff --git a/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java b/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java new file mode 100644 index 00000000000..22aa700ce8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JasmineDragonTeaShop.java @@ -0,0 +1,83 @@ +package mage.cards.j; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +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.CreateTokenEffect; +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.SubType; +import mage.game.Game; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JasmineDragonTeaShop extends CardImpl { + + public JasmineDragonTeaShop(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any color. Spend this mana only to cast an Ally spell or activate an ability of an Ally source. + this.addAbility(new ConditionalAnyColorManaAbility(1, new JasmineDragonTeaShopManaBuilder())); + + // {5}, {T}: Create a 1/1 white Ally creature token. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new AllyToken()), new GenericManaCost(5)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private JasmineDragonTeaShop(final JasmineDragonTeaShop card) { + super(card); + } + + @Override + public JasmineDragonTeaShop copy() { + return new JasmineDragonTeaShop(this); + } +} + +class JasmineDragonTeaShopManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new JasmineDragonTeaShopConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast an Ally spell or activate an ability of an Ally source"; + } +} + +class JasmineDragonTeaShopConditionalMana extends ConditionalMana { + + JasmineDragonTeaShopConditionalMana(Mana mana) { + super(mana); + addCondition(JasmineDragonTeaShopCondition.instance); + } +} + +enum JasmineDragonTeaShopCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = game.getObject(source); + return object != null && object.hasSubtype(SubType.ALLY, game) && !source.isActivated(); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JechtReluctantGuardian.java b/Mage.Sets/src/mage/cards/j/JechtReluctantGuardian.java index 5cb0bcea09c..79a0a08458f 100644 --- a/Mage.Sets/src/mage/cards/j/JechtReluctantGuardian.java +++ b/Mage.Sets/src/mage/cards/j/JechtReluctantGuardian.java @@ -1,43 +1,64 @@ package mage.cards.j; -import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class JechtReluctantGuardian extends CardImpl { +public final class JechtReluctantGuardian extends TransformingDoubleFacedCard { public JechtReluctantGuardian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR}, "{3}{B}", + "Braska's Final Aeon", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.NIGHTMARE}, "B"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BraskasFinalAeon.class; + // Jecht, Reluctant Guardian + this.getLeftHalfCard().setPT(4, 3); // Menace - this.addAbility(new MenaceAbility()); + this.getLeftHalfCard().addAbility(new MenaceAbility()); // Whenever Jecht deals combat damage to a player, you may exile it, then return it to the battlefield transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED) .setText("exile it, then return it to the battlefield transformed under its owner's control"), true )); + + // Braska's Final Aeon + this.getRightHalfCard().setPT(7, 7); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I, II -- Jecht Beam -- Each opponent discards a card and you draw a card. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { + ability.addEffect(new DiscardEachPlayerEffect(TargetController.OPPONENT)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and you")); + ability.withFlavorWord("Jecht Beam"); + }); + + // III -- Ultimate Jecht Shot -- Each opponent sacrifices two creatures of their choice. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, ability -> { + ability.addEffect(new SacrificeOpponentsEffect(2, StaticFilters.FILTER_PERMANENT_CREATURES)); + ability.withFlavorWord("Ultimate Jecht Shot"); + }); + this.getRightHalfCard().addAbility(sagaAbility.withShowSacText(true)); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); } private JechtReluctantGuardian(final JechtReluctantGuardian card) { diff --git a/Mage.Sets/src/mage/cards/j/JeongJeongTheDeserter.java b/Mage.Sets/src/mage/cards/j/JeongJeongTheDeserter.java new file mode 100644 index 00000000000..c5e1fc61e9f --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JeongJeongTheDeserter.java @@ -0,0 +1,59 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.delayed.CopyNextSpellDelayedTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.ExhaustAbility; +import mage.abilities.keyword.FirebendingAbility; +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.FilterSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JeongJeongTheDeserter extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a Lesson spell"); + + static { + filter.add(SubType.LESSON.getPredicate()); + } + + public JeongJeongTheDeserter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // Exhaust -- {3}: Put a +1/+1 counter on Jeong Jeong. When you next cast a Lesson spell this turn, copy it and you may choose new targets for the copy. + Ability ability = new ExhaustAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(3)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new CopyNextSpellDelayedTriggeredAbility(filter))); + this.addAbility(ability); + } + + private JeongJeongTheDeserter(final JeongJeongTheDeserter card) { + super(card); + } + + @Override + public JeongJeongTheDeserter copy() { + return new JeongJeongTheDeserter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java index 606bec7fe1e..1c3ece7ad3e 100644 --- a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java +++ b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java @@ -1,24 +1,23 @@ package mage.cards.j; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.*; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -33,35 +32,45 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class JerrenCorruptedBishop extends CardImpl { +public final class JerrenCorruptedBishop extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent(SubType.HUMAN); public JerrenCorruptedBishop(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{2}{B}", + "Ormendahl, the Corrupter", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.o.OrmendahlTheCorrupter.class; + // Jerren, Corrupted Bishop + this.getLeftHalfCard().setPT(2, 3); // Whenever Jerren, Corrupted Bishop enters the battlefield or another nontoken Human you control dies, you lose 1 life and create a 1/1 white Human creature token. - this.addAbility(new JerrenCorruptedBishopTriggeredAbility()); + this.getLeftHalfCard().addAbility(new JerrenCorruptedBishopTriggeredAbility()); // {2}: Target Human you control gains lifelink until end of turn. Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( LifelinkAbility.getInstance(), Duration.EndOfTurn ), new GenericManaCost(2)); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - - // At the beginning of your end step, if you have exactly 13 life, you may pay {4}{B}{B}. If you do, transform Jerren. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new DoIfCostPaid( + this.getLeftHalfCard().addAbility(ability); + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new DoIfCostPaid( new TransformSourceEffect(), new ManaCostsImpl<>("{4}{B}{B}") ), false, JerrenCorruptedBishopCondition.instance)); + + // Ormendahl, the Corrupter + this.getRightHalfCard().setPT(6, 6); + + // Flying, Trample, Lifelink + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Sacrifice another creature: Draw a card. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), + new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) + )); } private JerrenCorruptedBishop(final JerrenCorruptedBishop card) { @@ -125,7 +134,6 @@ class JerrenCorruptedBishopTriggeredAbility extends TriggeredAbilityImpl { && zEvent.getTarget().isControlledBy(getControllerId()) && !(zEvent.getTarget() instanceof PermanentToken) && zEvent.getTarget().hasSubtype(SubType.HUMAN, game); - default: return false; } diff --git a/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java b/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java index 5a4a488cc07..71f62bc2e88 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiRevelation.java @@ -22,9 +22,7 @@ public final class JeskaiRevelation extends CardImpl { // Return target spell or permanent to its owner's hand. Jeskai Revelation deals 4 damage to any target. Create two 1/1 white Monk creature tokens with prowess. Draw two cards. You gain 4 life. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetSpellOrPermanent()); - this.getSpellAbility().addEffect(new DamageTargetEffect( - 4, true, "any target", true - ).setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new CreateTokenEffect(new MonasteryMentorToken(), 2)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index bb34acdfccd..482244ee81e 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -165,9 +165,9 @@ class JestersScepterCost extends CostImpl { if (card instanceof SplitCard) { game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName()); game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName()); - } else if (card instanceof ModalDoubleFacedCard) { - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((ModalDoubleFacedCard) card).getLeftHalfCard().getName()); - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((ModalDoubleFacedCard) card).getRightHalfCard().getName()); + } else if (card instanceof DoubleFacedCard) { + game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((DoubleFacedCard) card).getLeftHalfCard().getName()); + game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((DoubleFacedCard) card).getRightHalfCard().getName()); } else { game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", card.getName()); } diff --git a/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java b/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java new file mode 100644 index 00000000000..d1427af3158 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetFreedomFighter.java @@ -0,0 +1,59 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.DamageTargetEffect; +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.SuperType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetFreedomFighter extends CardImpl { + + public JetFreedomFighter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/W}{R/W}{R/W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Jet enters, he deals damage equal to the number of creatures you control to target creature an opponent controls. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(CreaturesYouControlCount.PLURAL) + .setText("he deals damage equal to the number of creatures " + + "you control to target creature an opponent controls") + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // When Jet dies, put a +1/+1 counter on each of up to two target creatures. + ability = new DiesSourceTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent(0, 2)); + this.addAbility(ability); + } + + private JetFreedomFighter(final JetFreedomFighter card) { + super(card); + } + + @Override + public JetFreedomFighter copy() { + return new JetFreedomFighter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JetRebelLeader.java b/Mage.Sets/src/mage/cards/j/JetRebelLeader.java new file mode 100644 index 00000000000..ff558865f8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetRebelLeader.java @@ -0,0 +1,50 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetRebelLeader extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 3 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public JetRebelLeader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Whenever Jet attacks, look at the top five cards of your library. You may put a creature card with mana value 3 or less from among them onto the battlefield tapped and attacking. Put the rest on the bottom of your library in a random order. + this.addAbility(new AttacksTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, filter, PutCards.BATTLEFIELD_TAPPED_ATTACKING, PutCards.BOTTOM_RANDOM + ))); + } + + private JetRebelLeader(final JetRebelLeader card) { + super(card); + } + + @Override + public JetRebelLeader copy() { + return new JetRebelLeader(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JetfireAirGuardian.java b/Mage.Sets/src/mage/cards/j/JetfireAirGuardian.java deleted file mode 100644 index 4b13db01518..00000000000 --- a/Mage.Sets/src/mage/cards/j/JetfireAirGuardian.java +++ /dev/null @@ -1,58 +0,0 @@ -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.common.TransformSourceEffect; -import mage.abilities.effects.keyword.AdaptEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LivingMetalAbility; -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 JetfireAirGuardian extends CardImpl { - - public JetfireAirGuardian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // {U}{U}{U}: Convert Jetfire, then adapt 3. - Ability ability = new SimpleActivatedAbility( - new TransformSourceEffect() - .setText("convert {this}"), - new ManaCostsImpl<>("{U}{U}{U}") - ); - ability.addEffect(new AdaptEffect(3).concatBy(", then")); - this.addAbility(ability); - } - - private JetfireAirGuardian(final JetfireAirGuardian card) { - super(card); - } - - @Override - public JetfireAirGuardian copy() { - return new JetfireAirGuardian(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JetfireIngeniousScientist.java b/Mage.Sets/src/mage/cards/j/JetfireIngeniousScientist.java index 14fe70380a6..e3280a8e28d 100644 --- a/Mage.Sets/src/mage/cards/j/JetfireIngeniousScientist.java +++ b/Mage.Sets/src/mage/cards/j/JetfireIngeniousScientist.java @@ -1,18 +1,20 @@ package mage.cards.j; -import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.RemoveVariableCountersTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.keyword.AdaptEffect; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -30,22 +32,22 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class JetfireIngeniousScientist extends CardImpl { +public final class JetfireIngeniousScientist extends TransformingDoubleFacedCard { public JetfireIngeniousScientist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{4}{U}", + "Jetfire, Air Guardian", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "U"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.j.JetfireAirGuardian.class; + // Jetfire, Ingenious Scientist + this.getLeftHalfCard().setPT(3, 4); // More Than Meets the Eye {3}{U} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{U}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{3}{U}")); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Remove one or more +1/+1 counters from among artifacts you control: Target player adds that much {C}. This mana can't be spent to cast nonartifact spells. Convert Jetfire. Ability ability = new SimpleActivatedAbility( @@ -57,7 +59,25 @@ public final class JetfireIngeniousScientist extends CardImpl { ); ability.addEffect(new TransformSourceEffect().setText("convert {this}")); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Jetfire, Air Guardian + this.getRightHalfCard().setPT(3, 4); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // {U}{U}{U}: Convert Jetfire, then adapt 3. + Ability backAbility = new SimpleActivatedAbility( + new TransformSourceEffect() + .setText("convert {this}"), + new ManaCostsImpl<>("{U}{U}{U}") + ); + backAbility.addEffect(new AdaptEffect(3).concatBy(", then")); + this.getRightHalfCard().addAbility(backAbility); } private JetfireIngeniousScientist(final JetfireIngeniousScientist card) { diff --git a/Mage.Sets/src/mage/cards/j/JetsBrainwashing.java b/Mage.Sets/src/mage/cards/j/JetsBrainwashing.java new file mode 100644 index 00000000000..5c303a6e71d --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetsBrainwashing.java @@ -0,0 +1,56 @@ +package mage.cards.j; + +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.KickerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetsBrainwashing extends CardImpl { + + public JetsBrainwashing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Kicker {3} + this.addAbility(new KickerAbility("{3}")); + + // Target creature can't block this turn. If this spell was kicked, gain control of that creature until end of turn, untap it, and it gains haste until end of turn. + this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new AddContinuousEffectToGame( + new GainControlTargetEffect(Duration.EndOfTurn), + new GainAbilityTargetEffect(HasteAbility.getInstance()) + ), KickedCondition.ONCE, "If this spell was kicked, gain control of that creature " + + "until end of turn, untap it, and it gains haste until end of turn" + ).addEffect(new UntapTargetEffect())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Create a Clue token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("
")); + } + + private JetsBrainwashing(final JetsBrainwashing card) { + super(card); + } + + @Override + public JetsBrainwashing copy() { + return new JetsBrainwashing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JillShivasDominant.java b/Mage.Sets/src/mage/cards/j/JillShivasDominant.java index c115eba3121..7f4874f9200 100644 --- a/Mage.Sets/src/mage/cards/j/JillShivasDominant.java +++ b/Mage.Sets/src/mage/cards/j/JillShivasDominant.java @@ -1,61 +1,82 @@ package mage.cards.j; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class JillShivasDominant extends CardImpl { +public final class JillShivasDominant extends TransformingDoubleFacedCard { - private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanent"); + private static final FilterPermanent filterFront = new FilterNonlandPermanent("other target nonland permanent"); + private static final FilterPermanent filterLandsOpponents = new FilterLandPermanent("lands your opponents control"); static { - filter.add(AnotherPredicate.instance); + filterFront.add(AnotherPredicate.instance); + filterLandsOpponents.add(TargetController.OPPONENT.getControllerPredicate()); } public JillShivasDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WARRIOR}, "{2}{U}", + "Shiva, Warden of Ice", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.ELEMENTAL}, "U"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.s.ShivaWardenOfIce.class; + // Jill, Shiva's Dominant (front) + this.getLeftHalfCard().setPT(2, 2); // When Jill enters, return up to one other target nonland permanent to its owner's hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetPermanent(0, 1, filter)); - this.addAbility(ability); + ability.addTarget(new TargetPermanent(0, 1, filterFront)); + this.getLeftHalfCard().addAbility(ability); // {3}{U}{U}, {T}: Exile Jill, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - ability = new ActivateAsSorceryActivatedAbility( + Ability transformAbility = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{3}{U}{U}") ); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); + transformAbility.addCost(new TapSourceCost()); + this.getLeftHalfCard().addAbility(transformAbility); + + // Shiva, Warden of Ice (back) + this.getRightHalfCard().setPT(4, 5); + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I, II -- Mesmerize -- Target creature can't be blocked this turn. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new CantBeBlockedTargetEffect(Duration.EndOfTurn)); + sagaChapterAbility.addTarget(new TargetCreaturePermanent()); + sagaChapterAbility.withFlavorWord("Mesmerize"); + }); + + // III -- Cold Snap -- Tap all lands your opponents control. Exile Shiva, then return it to the battlefield. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, sagaChapterAbility -> { + sagaChapterAbility.addEffect(new TapAllEffect(filterLandsOpponents)); + sagaChapterAbility.addEffect(new ExileSourceAndReturnFaceUpEffect()); + sagaChapterAbility.withFlavorWord("Cold Snap"); + }); + this.getRightHalfCard().addAbility(sagaAbility); } private JillShivasDominant(final JillShivasDominant card) { diff --git a/Mage.Sets/src/mage/cards/j/JinGitaxias.java b/Mage.Sets/src/mage/cards/j/JinGitaxias.java index 6fd9909cef0..4bf0fed7d17 100644 --- a/Mage.Sets/src/mage/cards/j/JinGitaxias.java +++ b/Mage.Sets/src/mage/cards/j/JinGitaxias.java @@ -1,58 +1,92 @@ package mage.cards.j; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.keyword.WardAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; import java.util.UUID; -public class JinGitaxias extends CardImpl { +public class JinGitaxias extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("a noncreature spell with mana value 3 or greater"); + private static final FilterCreaturePermanent filterNonPhyrexian = new FilterCreaturePermanent("non-Phyrexian creatures"); static { filter.add(Predicates.not(CardType.CREATURE.getPredicate())); filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 2)); + filterNonPhyrexian.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); } public JinGitaxias(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); - this.supertype.add(SuperType.LEGENDARY); - this.addSubType(SubType.PHYREXIAN); - this.addSubType(SubType.PRAETOR); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.t.TheGreatSynthesis.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{3}{U}{U}", + "The Great Synthesis", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "U"); - //Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + // Jin-Gitaxias + this.getLeftHalfCard().setPT(5, 5); - //Whenever you cast a noncreature spell with mana value 3 or greater, draw a card. - this.addAbility(new SpellCastControllerTriggeredAbility( - new DrawCardSourceControllerEffect(1), - filter, false + // Ward {2} + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + + // Whenever you cast a noncreature spell with mana value 3 or greater, draw a card. + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, false )); - //{3}{U}: Exile Jin-Gitaxias, then return it to the battlefield transformed under its owner’s control. Activate - //only as a sorcery and only if you have seven or more cards in hand. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + // {3}{U}: Exile Jin-Gitaxias, then return it to the battlefield transformed under its owner’s control. Activate only as a sorcery and only if you have seven or more cards in hand. + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{3}{U}"), new CardsInHandCondition(ComparisonType.MORE_THAN, 6) ).setTiming(TimingRule.SORCERY)); + + // The Great Synthesis + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I — Draw cards equal to the number of cards in your hand. You have no maximum hand size for as long as you control The Great Synthesis. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, + new DrawCardSourceControllerEffect(CardsInControllerHandCount.ANY) + .setText("draw cards equal to the number of cards in your hand"), + new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET) + .setText("you have no maximum hand size for as long as you control {this}")); + + // II — Return all non-Phyrexian creatures to their owners' hands. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_II, new ReturnToHandFromBattlefieldAllEffect(filterNonPhyrexian)); + + // III — You may cast any number of spells from your hand without paying their mana cost. Exile The Great Synthesis, then return it to the battlefield (front face up). + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new TheGreatSynthesisCastEffect(), + new ExileSourceAndReturnFaceUpEffect() + ); + this.getRightHalfCard().addAbility(sagaAbility); } private JinGitaxias(final JinGitaxias card) { @@ -64,3 +98,30 @@ public class JinGitaxias extends CardImpl { return new JinGitaxias(this); } } + +class TheGreatSynthesisCastEffect extends OneShotEffect { + public TheGreatSynthesisCastEffect() { + super(Outcome.PlayForFree); + this.staticText = "you may cast any number of spells from your hand without paying their mana costs"; + } + + private TheGreatSynthesisCastEffect(final TheGreatSynthesisCastEffect effect) { + super(effect); + } + + @Override + public TheGreatSynthesisCastEffect copy() { + return new TheGreatSynthesisCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = controller.getHand(); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JinSakaiGhostOfTsushima.java b/Mage.Sets/src/mage/cards/j/JinSakaiGhostOfTsushima.java new file mode 100644 index 00000000000..4839a8ce934 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JinSakaiGhostOfTsushima.java @@ -0,0 +1,116 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.MageItem; +import mage.abilities.Mode; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +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.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JinSakaiGhostOfTsushima extends CardImpl { + + public JinSakaiGhostOfTsushima(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SAMURAI); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever Jin Sakai deals combat damage to a player, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // Whenever a creature you control attacks a player, if no other creatures are attacking that player, choose one -- + // * Standoff -- It gains double strike until end of turn. + // * Ghost -- It can't be blocked this turn. + this.addAbility(new JinSakaiGhostOfTsushimaTriggeredAbility()); + } + + private JinSakaiGhostOfTsushima(final JinSakaiGhostOfTsushima card) { + super(card); + } + + @Override + public JinSakaiGhostOfTsushima copy() { + return new JinSakaiGhostOfTsushima(this); + } +} + +class JinSakaiGhostOfTsushimaTriggeredAbility extends TriggeredAbilityImpl { + + JinSakaiGhostOfTsushimaTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()).withTargetDescription("it")); + this.withFirstModeFlavorWord("Standoff"); + this.addMode(new Mode(new CantBeBlockedTargetEffect().withTargetDescription("it")).withFlavorWord("Ghost")); + this.setTriggerPhrase("Whenever a creature you control attacks a player, if no other creatures are attacking that player, "); + } + + private JinSakaiGhostOfTsushimaTriggeredAbility(final JinSakaiGhostOfTsushimaTriggeredAbility ability) { + super(ability); + } + + @Override + public JinSakaiGhostOfTsushimaTriggeredAbility copy() { + return new JinSakaiGhostOfTsushimaTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null + || !permanent.isControlledBy(getControllerId()) + || game.getPlayer(game.getCombat().getDefenderId(permanent.getId())) == null) { + return false; + } + this.getAllEffects().setTargetPointer(new FixedTarget(permanent, game)); + return true; + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return this + .getAllEffects() + .stream() + .map(Effect::getTargetPointer) + .map(targetPointer -> targetPointer.getFirst(game, this)) + .map(game::getPermanent) + .filter(Objects::nonNull) + .findAny() + .map(MageItem::getId) + .map(game.getCombat()::getDefenderId) + .filter(defenderId -> game + .getCombat() + .getAttackers() + .stream() + .map(game.getCombat()::getDefenderId) + .filter(defenderId::equals) + .count() == 1) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java b/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java index 213fa766283..786e680c57e 100644 --- a/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java +++ b/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java @@ -6,10 +6,10 @@ import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.PartnerVariantType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; @@ -43,7 +43,7 @@ public final class JoelResoluteSurvivor extends CardImpl { this.addAbility(ability); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private JoelResoluteSurvivor(final JoelResoluteSurvivor card) { diff --git a/Mage.Sets/src/mage/cards/j/JooDeeOneOfMany.java b/Mage.Sets/src/mage/cards/j/JooDeeOneOfMany.java new file mode 100644 index 00000000000..1736af86532 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JooDeeOneOfMany.java @@ -0,0 +1,52 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.CreateTokenCopySourceEffect; +import mage.abilities.effects.common.SacrificeControllerEffect; +import mage.abilities.effects.keyword.SurveilEffect; +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 JooDeeOneOfMany extends CardImpl { + + public JooDeeOneOfMany(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {B}, {T}: Surveil 1. Create a token that's a copy of this creature, then sacrifice an artifact or creature. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new SurveilEffect(1, false), new ManaCostsImpl<>("{B}") + ); + ability.addCost(new TapSourceCost()); + ability.addEffect(new CreateTokenCopySourceEffect()); + ability.addEffect(new SacrificeControllerEffect( + StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE, 1, ", then" + )); + this.addAbility(ability); + } + + private JooDeeOneOfMany(final JooDeeOneOfMany card) { + super(card); + } + + @Override + public JooDeeOneOfMany copy() { + return new JooDeeOneOfMany(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JoshuaPhoenixsDominant.java b/Mage.Sets/src/mage/cards/j/JoshuaPhoenixsDominant.java index bcc50be49c0..9db4bba6ead 100644 --- a/Mage.Sets/src/mage/cards/j/JoshuaPhoenixsDominant.java +++ b/Mage.Sets/src/mage/cards/j/JoshuaPhoenixsDominant.java @@ -1,49 +1,82 @@ package mage.cards.j; -import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** * @author TheElk801 */ -public final class JoshuaPhoenixsDominant extends CardImpl { +public final class JoshuaPhoenixsDominant extends TransformingDoubleFacedCard { public JoshuaPhoenixsDominant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WIZARD}, "{1}{R}{W}", + "Phoenix, Warden of Fire", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.PHOENIX}, "RW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.p.PhoenixWardenOfFire.class; + // Joshua, Phoenix's Dominant + this.getLeftHalfCard().setPT(3, 4); // When Joshua enters, discard up to two cards, then draw that many cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardAndDrawThatManyEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DiscardAndDrawThatManyEffect(2))); // {3}{R}{W}, {T}: Exile Joshua, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{3}{R}{W}") ); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Phoenix, Warden of Fire + this.getRightHalfCard().setPT(4, 4); + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I, II -- Rising Flames -- Phoenix deals 2 damage to each opponent. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, chapter -> { + chapter.addEffect(new DamagePlayersEffect(2, TargetController.OPPONENT)); + chapter.withFlavorWord("Rising Flames"); + }); + + // III -- Flames of Rebirth -- Return any number of target creature cards with total mana value 6 or less from your graveyard to the battlefield. Exile Phoenix, then return it to the battlefield. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_III, chapter -> { + chapter.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + chapter.addEffect(new ExileSourceAndReturnFaceUpEffect()); + chapter.addTarget(new PhoenixWardenOfFireTarget()); + chapter.withFlavorWord("Flames of Rebirth"); + }); + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); } private JoshuaPhoenixsDominant(final JoshuaPhoenixsDominant card) { @@ -55,3 +88,53 @@ public final class JoshuaPhoenixsDominant extends CardImpl { return new JoshuaPhoenixsDominant(this); } } + +class PhoenixWardenOfFireTarget extends TargetCardInYourGraveyard { + + private static final FilterCard filterStatic = new FilterCreatureCard( + "creature cards with total mana value 6 or less from your graveyard" + ); + + PhoenixWardenOfFireTarget() { + super(0, Integer.MAX_VALUE, filterStatic, false); + } + + private PhoenixWardenOfFireTarget(final PhoenixWardenOfFireTarget target) { + super(target); + } + + @Override + public PhoenixWardenOfFireTarget copy() { + return new PhoenixWardenOfFireTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + return super.canTarget(playerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 6, game + ); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit( + this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 6, game + ); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this + .getTargets() + .stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JourneyToEternity.java b/Mage.Sets/src/mage/cards/j/JourneyToEternity.java index f3759a3341d..132be3c70e8 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyToEternity.java +++ b/Mage.Sets/src/mage/cards/j/JourneyToEternity.java @@ -3,47 +3,60 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; +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.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.AnyColorManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author LevelX2 */ -public final class JourneyToEternity extends CardImpl { +public final class JourneyToEternity extends TransformingDoubleFacedCard { public JourneyToEternity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "{1}{B}{G}", + "Atzal, Cave of Eternity", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AURA); - - this.secondSideCardClazz = mage.cards.a.AtzalCaveOfEternity.class; - - // Enchant creature you control + // Journey to Eternity TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); + this.getLeftHalfCard().getSpellAbility().addTarget(auraTarget); + this.getLeftHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getLeftHalfCard().addAbility(new EnchantAbility(auraTarget)); // When enchanted creature dies, return it to the battlefield under your control, then return Journey to Eternity to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); Ability ability = new DiesAttachedTriggeredAbility(new ReturnToBattlefieldUnderYourControlAttachedEffect("it"), "enchanted creature"); ability.addEffect(new JourneyToEternityReturnTransformedSourceEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + // Atzal, Cave of Eternity + + // {T}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); + + // {3}{B}{G}, {T}: Return target creature card from your graveyard to the battlefield. + Ability backAbility = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{3}{B}{G}")); + backAbility.addCost(new TapSourceCost()); + backAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(backAbility); } private JourneyToEternity(final JourneyToEternity card) { diff --git a/Mage.Sets/src/mage/cards/j/JudgmentBolt.java b/Mage.Sets/src/mage/cards/j/JudgmentBolt.java index d0581aa5d85..164fc2740aa 100644 --- a/Mage.Sets/src/mage/cards/j/JudgmentBolt.java +++ b/Mage.Sets/src/mage/cards/j/JudgmentBolt.java @@ -1,16 +1,19 @@ package mage.cards.j; +import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; 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.Outcome; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -20,16 +23,14 @@ import java.util.UUID; */ public final class JudgmentBolt extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.EQUIPMENT)); + static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.EQUIPMENT)); private static final Hint hint = new ValueHint("Equipment you control", xValue); public JudgmentBolt(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Judgment Bolt deals 5 damage to target creature and X damage to that creature's controller, where X is the number of Equipment you control. - this.getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellAbility().addEffect(new DamageTargetControllerEffect(xValue) - .setText("and X damage to that creature's controller, where X is the number of Equipment you control")); + this.getSpellAbility().addEffect(new JudgmentBoltEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addHint(hint); } @@ -43,3 +44,28 @@ public final class JudgmentBolt extends CardImpl { return new JudgmentBolt(this); } } + +// too lazy to handle dynamic value properly in the common class +class JudgmentBoltEffect extends OneShotEffect { + + JudgmentBoltEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 5 damage to target creature and X damage to that creature's controller," + + " where X is the number of Equipment you control"; + } + + private JudgmentBoltEffect(final JudgmentBoltEffect effect) { + super(effect); + } + + @Override + public JudgmentBoltEffect copy() { + return new JudgmentBoltEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return new DamageTargetAndTargetControllerEffect(5, JudgmentBolt.xValue.calculate(game, source, this)) + .apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java b/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java index 0ccc1720602..39115c686df 100644 --- a/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java +++ b/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java @@ -1,51 +1,104 @@ package mage.cards.j; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SagaAbility; +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.CreateTokenEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SagaChapter; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +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.game.permanent.token.HumanMonkToken; +import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author TheElk801 */ -public final class JuganDefendsTheTemple extends CardImpl { +public final class JuganDefendsTheTemple extends TransformingDoubleFacedCard { + + private static final FilterPermanent filterModified = new FilterControlledCreaturePermanent(); + + static { + filterModified.add(ModifiedPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filterModified, ComparisonType.MORE_THAN, 4); + private static final Hint hint = new ValueHint("Modified creatures you control", new PermanentsOnBattlefieldCount(filterModified)); public JuganDefendsTheTemple(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{G}", + "Remnant of the Rising Star", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.DRAGON, SubType.SPIRIT}, "G"); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.r.RemnantOfTheRisingStar.class; + // Jugan Defends the Temple // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Create a 1/1 green Human Monk creature token with "{T}: Add {G}." - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new HumanMonkToken())); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), 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, + this.getLeftHalfCard(), 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Remnant of the Rising Star + this.getRightHalfCard().setPT(2, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever another creature you control enters, you may pay {X}. When you do, put X +1/+1 counters on that creature. + this.getRightHalfCard().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 staticAbility = 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" + )); + staticAbility.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), condition, "and has trample" + )); + this.getRightHalfCard().addAbility(staticAbility.addHint(hint)); } private JuganDefendsTheTemple(final JuganDefendsTheTemple card) { @@ -57,3 +110,45 @@ public final class JuganDefendsTheTemple extends CardImpl { return new JuganDefendsTheTemple(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.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to add counters)", game, source, true); + 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/j/JuneBountyHunter.java b/Mage.Sets/src/mage/cards/j/JuneBountyHunter.java new file mode 100644 index 00000000000..afe5ebc8378 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JuneBountyHunter.java @@ -0,0 +1,60 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DrewTwoOrMoreCardsCondition; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.CreateTokenEffect; +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.SuperType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JuneBountyHunter extends CardImpl { + + public JuneBountyHunter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // June can't be blocked as long as you've drawn two or more cards this turn. + this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedSourceEffect(), DrewTwoOrMoreCardsCondition.instance, + "{this} can't be blocked as long as you've drawn two or more cards this turn" + ))); + + // {1}, Sacrifice another creature: Create a Clue token. Activate only during your turn. + Ability ability = new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new ClueArtifactToken()), new GenericManaCost(1), MyTurnCondition.instance + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private JuneBountyHunter(final JuneBountyHunter card) { + super(card); + } + + @Override + public JuneBountyHunter copy() { + return new JuneBountyHunter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JurassicPark.java b/Mage.Sets/src/mage/cards/j/JurassicPark.java deleted file mode 100644 index 7024769e637..00000000000 --- a/Mage.Sets/src/mage/cards/j/JurassicPark.java +++ /dev/null @@ -1,107 +0,0 @@ -package mage.cards.j; - -import java.util.Objects; -import java.util.UUID; - -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.EscapeAbility; -import mage.abilities.mana.DynamicManaAbility; -import mage.constants.*; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; -import mage.players.Player; - -/** - * - * @author jimga150 - */ -public final class JurassicPark extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledPermanent("Dinosaur you control"); - - static { - filter.add(SubType.DINOSAUR.getPredicate()); - } - - private static final Hint hint = new ValueHint( - "Number of Dinosaurs you control", new PermanentsOnBattlefieldCount(filter) - ); - - public JurassicPark(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // (Transforms from Welcome to ....) - // Each Dinosaur card in your graveyard has escape. The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard. - // Based on Underworld Breach - this.addAbility(new SimpleStaticAbility(new JurassicParkEffect())); - - // {T}: Add {G} for each Dinosaur you control. - // Based on Gaea's Cradle - DynamicManaAbility ability = new DynamicManaAbility( - Mana.GreenMana(1), - new PermanentsOnBattlefieldCount(filter) - ); - this.addAbility(ability.addHint(hint)); - } - - private JurassicPark(final JurassicPark card) { - super(card); - } - - @Override - public JurassicPark copy() { - return new JurassicPark(this); - } -} - -class JurassicParkEffect extends ContinuousEffectImpl { - - JurassicParkEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "Each Dinosaur card in your graveyard has escape. " + - "The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard."; - } - - private JurassicParkEffect(final JurassicParkEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - controller - .getGraveyard() - .getCards(game) - .stream() - .filter(Objects::nonNull) - .filter(card -> !card.getManaCost().getText().isEmpty()) // card must have a mana cost - .filter(card -> card.hasSubtype(SubType.DINOSAUR, game)) - .forEach(card -> { - Ability ability = new EscapeAbility(card, card.getManaCost().getText(), 3); - ability.setSourceId(card.getId()); - ability.setControllerId(card.getOwnerId()); - game.getState().addOtherAbility(card, ability); - }); - return true; - } - - @Override - public JurassicParkEffect copy() { - return new JurassicParkEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KamahlsSledge.java b/Mage.Sets/src/mage/cards/k/KamahlsSledge.java index 2349adb94c2..38f2f014855 100644 --- a/Mage.Sets/src/mage/cards/k/KamahlsSledge.java +++ b/Mage.Sets/src/mage/cards/k/KamahlsSledge.java @@ -2,7 +2,7 @@ package mage.cards.k; import mage.abilities.condition.common.ThresholdCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.DamageTargetControllerEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -21,15 +21,16 @@ public final class KamahlsSledge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{R}{R}"); // Kamahl's Sledge deals 4 damage to target creature. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - // Threshold - If seven or more cards are in your graveyard, instead Kamahl's Sledge deals 4 damage to that creature and 4 damage to that creature's controller. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetControllerEffect(4), ThresholdCondition.instance, "
" + - AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, " + - "instead {this} deals 4 damage to that creature and 4 damage to that creature's controller." + new DamageTargetAndTargetControllerEffect(4, 4), + new DamageTargetEffect(4), + ThresholdCondition.instance, + "{this} deals 4 damage to target creature.
" + + AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, " + + "instead {this} deals 4 damage to that creature and 4 damage to that creature's controller." )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } private KamahlsSledge(final KamahlsSledge card) { diff --git a/Mage.Sets/src/mage/cards/k/KappaCannoneer.java b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java index a2c29c94268..5094609202b 100644 --- a/Mage.Sets/src/mage/cards/k/KappaCannoneer.java +++ b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java @@ -43,7 +43,7 @@ public final class KappaCannoneer extends CardImpl { StaticFilters.FILTER_PERMANENT_ARTIFACT, false, true ); ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn) - .setText("and it can't be blocked this turn")); + .setText("It can't be blocked this turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KaslemsStonetree.java b/Mage.Sets/src/mage/cards/k/KaslemsStonetree.java index 7826274a53c..1c3efd9f7cf 100644 --- a/Mage.Sets/src/mage/cards/k/KaslemsStonetree.java +++ b/Mage.Sets/src/mage/cards/k/KaslemsStonetree.java @@ -3,8 +3,8 @@ package mage.cards.k; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.PutCards; import mage.constants.SubType; @@ -15,23 +15,30 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class KaslemsStonetree extends CardImpl { +public final class KaslemsStonetree extends TransformingDoubleFacedCard { public KaslemsStonetree(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}"); - this.secondSideCardClazz = mage.cards.k.KaslemsStrider.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{G}", + "Kaslem's Strider", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "G" + ); + // Kaslem's Stonetree // When Kaslem's Stonetree enters the battlefield, look at the top six cards of your library. You may put a land card from among them onto the battlefield tapped. Put the rest on the bottom in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( 6, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.BATTLEFIELD_TAPPED, PutCards.BOTTOM_RANDOM ))); // Craft with Cave {5}{G} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{5}{G}", "Cave", "another Cave you " + "control or a Cave card in your graveyard", SubType.CAVE.getPredicate() )); + + // Kaslem's Strider + this.getRightHalfCard().setPT(5, 5); } private KaslemsStonetree(final KaslemsStonetree card) { diff --git a/Mage.Sets/src/mage/cards/k/KaslemsStrider.java b/Mage.Sets/src/mage/cards/k/KaslemsStrider.java deleted file mode 100644 index 2bc73f92442..00000000000 --- a/Mage.Sets/src/mage/cards/k/KaslemsStrider.java +++ /dev/null @@ -1,34 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -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 KaslemsStrider extends CardImpl { - - public KaslemsStrider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setGreen(true); - } - - private KaslemsStrider(final KaslemsStrider card) { - super(card); - } - - @Override - public KaslemsStrider copy() { - return new KaslemsStrider(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java b/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java new file mode 100644 index 00000000000..62559da7617 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KataraSeekingRevenge.java @@ -0,0 +1,68 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.WaterbendAbility; +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.FilterCard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KataraSeekingRevenge extends CardImpl { + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON)); + + public KataraSeekingRevenge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U/B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // As an additional cost to cast this spell, you may waterbend {2}. + this.addAbility(new WaterbendAbility(2)); + + // When Katara enters, draw a card, then discard a card unless her additional cost was paid. + Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new ConditionalOneShotEffect( + null, new DiscardControllerEffect(1), WaterbendedCondition.instance, + ", then discard a card unless her additional cost was paid" + )); + this.addAbility(ability); + + // Katara gets +1/+1 for each Lesson card in your graveyard. + this.addAbility(new SimpleStaticAbility( + new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) + ).addHint(LessonsInGraveCondition.getHint())); + } + + private KataraSeekingRevenge(final KataraSeekingRevenge card) { + super(card); + } + + @Override + public KataraSeekingRevenge copy() { + return new KataraSeekingRevenge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java index 35f78ab4521..d637cb6b178 100644 --- a/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java +++ b/Mage.Sets/src/mage/cards/k/KataraWaterTribesHope.java @@ -9,6 +9,7 @@ import mage.abilities.costs.common.WaterbendCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessAllEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -49,6 +50,7 @@ public final class KataraWaterTribesHope extends CardImpl { GetXValue.instance, GetXValue.instance, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES ), new WaterbendCost("{X}"), MyTurnCondition.instance); + ability.addEffect(new InfoEffect("X can't be 0")); CardUtil.castStream(ability.getCosts(), VariableManaCost.class).forEach(cost -> cost.setMinX(1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KatarasReversal.java b/Mage.Sets/src/mage/cards/k/KatarasReversal.java new file mode 100644 index 00000000000..93af60adaa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KatarasReversal.java @@ -0,0 +1,47 @@ +package mage.cards.k; + +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.TargetStackObject; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KatarasReversal extends CardImpl { + + public KatarasReversal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + + // Counter up to four target spells and/or abilities. + this.getSpellAbility().addEffect(new CounterTargetEffect() + .setText("counter up to four target spells and/or abilities")); + this.getSpellAbility().addTarget(new TargetStackObject( + 0, 4, StaticFilters.FILTER_SPELL_OR_ABILITY + )); + + // Untap up to four target artifacts and/or creatures. + this.getSpellAbility().addEffect(new UntapTargetEffect() + .setTargetPointer(new SecondTargetPointer()) + .setText("
Untap up to four target artifacts and/or creatures")); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, 4, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE + )); + } + + private KatarasReversal(final KatarasReversal card) { + super(card); + } + + @Override + public KatarasReversal copy() { + return new KatarasReversal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java b/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java index 3a042a3aad7..b4d523c3ded 100644 --- a/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java +++ b/Mage.Sets/src/mage/cards/k/KatildaDawnhartMartyr.java @@ -1,29 +1,31 @@ package mage.cards.k; -import mage.MageInt; +import mage.abilities.Ability; 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.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.*; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class KatildaDawnhartMartyr extends CardImpl { +public final class KatildaDawnhartMartyr extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterPermanent(SubType.VAMPIRE, "Vampires"); @@ -41,31 +43,56 @@ public final class KatildaDawnhartMartyr extends CardImpl { private static final Hint hint = new ValueHint("Spirits and enchantments you control", xValue); public KatildaDawnhartMartyr(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WARLOCK}, "{1}{W}{W}", + "Katilda's Rising Dawn", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.secondSideCardClazz = mage.cards.k.KatildasRisingDawn.class; + // Katilda, Dawnhart Martyr + this.getLeftHalfCard().setPT(0, 0); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Protection from Vampires - this.addAbility(new ProtectionAbility(filter)); + this.getLeftHalfCard().addAbility(new ProtectionAbility(filter)); // Katilda, Dawnhart Martyr's power and toughness are each equal to the number of permanents you control that are Spirits and/or enchantments. - this.addAbility(new SimpleStaticAbility( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue) ).addHint(hint)); + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {3}{W}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}{W}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}{W}")); + + // Katilda's Rising Dawn + // Enchanted creature has flying, lifelink, and protection from Vampires, and it gets +X/+X where X is the number of permanents you control that are Spirits and/or enchantments. + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + )); + ability.addEffect(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.AURA + ).setText(", lifelink")); + ability.addEffect(new GainAbilityAttachedEffect( + new ProtectionAbility(filter), AttachmentType.AURA + ).setText(", and protection from Vampires")); + ability.addEffect(new BoostEquippedEffect(xValue, xValue) + .setText(", and it gets +X/+X, where X is the number of permanents you control that are Spirits and/or enchantments")); + this.getRightHalfCard().addAbility(ability.addHint(hint)); + + // If Katilda's Rising Dawn would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private KatildaDawnhartMartyr(final KatildaDawnhartMartyr card) { diff --git a/Mage.Sets/src/mage/cards/k/KatildasRisingDawn.java b/Mage.Sets/src/mage/cards/k/KatildasRisingDawn.java deleted file mode 100644 index dc2907dacea..00000000000 --- a/Mage.Sets/src/mage/cards/k/KatildasRisingDawn.java +++ /dev/null @@ -1,84 +0,0 @@ -package mage.cards.k; - -import mage.abilities.Ability; -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.BoostEquippedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.*; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class KatildasRisingDawn extends CardImpl { - - private static final FilterPermanent filter - = new FilterPermanent(SubType.VAMPIRE, "Vampires"); - private static final FilterPermanent filter2 - = new FilterControlledPermanent("permanents you control that are Spirits and/or enchantments"); - - static { - filter2.add(Predicates.or( - SubType.SPIRIT.getPredicate(), - CardType.ENCHANTMENT.getPredicate() - )); - } - - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter2); - private static final Hint hint = new ValueHint("Spirits and enchantments you control", xValue); - - public KatildasRisingDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has flying, lifelink, and protection from Vampires, and it gets +X/+X where X is the number of permanents you control that are Spirits and/or enchantments. - Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( - FlyingAbility.getInstance(), AttachmentType.AURA - )); - ability.addEffect(new GainAbilityAttachedEffect( - LifelinkAbility.getInstance(), AttachmentType.AURA - ).setText(", lifelink")); - ability.addEffect(new GainAbilityAttachedEffect( - new ProtectionAbility(filter), AttachmentType.AURA - ).setText(", and protection from Vampires")); - ability.addEffect(new BoostEquippedEffect(xValue, xValue) - .setText(", and it gets +X/+X, where X is the number of permanents you control that are Spirits and/or enchantments")); - this.addAbility(ability.addHint(hint)); - - // If Katilda's Rising Dawn would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private KatildasRisingDawn(final KatildasRisingDawn card) { - super(card); - } - - @Override - public KatildasRisingDawn copy() { - return new KatildasRisingDawn(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KederektParasite.java b/Mage.Sets/src/mage/cards/k/KederektParasite.java index 8242a79a6c7..e5c279bd776 100644 --- a/Mage.Sets/src/mage/cards/k/KederektParasite.java +++ b/Mage.Sets/src/mage/cards/k/KederektParasite.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.UUID; @@ -17,7 +16,6 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.targetpointer.FixedTarget; /** @@ -56,7 +54,7 @@ class KederektParasiteTriggeredAbility extends TriggeredAbilityImpl { } KederektParasiteTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "opponent"), true); + super(Zone.BATTLEFIELD, new DamageTargetEffect(1), true); } private KederektParasiteTriggeredAbility(final KederektParasiteTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/k/KefkaCourtMage.java b/Mage.Sets/src/mage/cards/k/KefkaCourtMage.java index 041856fd2c3..7b08db32161 100644 --- a/Mage.Sets/src/mage/cards/k/KefkaCourtMage.java +++ b/Mage.Sets/src/mage/cards/k/KefkaCourtMage.java @@ -1,19 +1,19 @@ package mage.cards.k; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.LoseLifeTriggeredAbility; +import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.SavedLifeLossValue; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.FlyingAbility; import mage.cards.*; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Controllable; import mage.game.Game; @@ -25,28 +25,38 @@ import java.util.*; /** * @author TheElk801 */ -public final class KefkaCourtMage extends CardImpl { +public final class KefkaCourtMage extends TransformingDoubleFacedCard { public KefkaCourtMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{2}{U}{B}{R}", + "Kefka, Ruler of Ruin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.WIZARD}, "UBR"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.k.KefkaRulerOfRuin.class; + // Kefka, Court Mage + this.getLeftHalfCard().setPT(4, 5); // Whenever Kefka enters or attacks, each player discards a card. Then you draw a card for each card type among cards discarded this way. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new KefkaCourtMageEffect())); + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new KefkaCourtMageEffect())); // {8}: Each opponent sacrifices a permanent of their choice. Transform Kefka. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT), new GenericManaCost(8) ); ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Kefka, Ruler of Ruin + this.getRightHalfCard().setPT(5, 7); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever an opponent loses life during your turn, you draw that many cards. + this.getRightHalfCard().addAbility(new LoseLifeTriggeredAbility( + new DrawCardSourceControllerEffect(SavedLifeLossValue.MANY, true), + TargetController.OPPONENT, false, false + ).withTriggerCondition(MyTurnCondition.instance)); } private KefkaCourtMage(final KefkaCourtMage card) { diff --git a/Mage.Sets/src/mage/cards/k/KefkaRulerOfRuin.java b/Mage.Sets/src/mage/cards/k/KefkaRulerOfRuin.java deleted file mode 100644 index aa642b63b2b..00000000000 --- a/Mage.Sets/src/mage/cards/k/KefkaRulerOfRuin.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.common.LoseLifeTriggeredAbility; -import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.dynamicvalue.common.SavedLifeLossValue; -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.constants.SuperType; -import mage.constants.TargetController; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class KefkaRulerOfRuin extends CardImpl { - - public KefkaRulerOfRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(5); - this.toughness = new MageInt(7); - this.nightCard = true; - this.color.setBlue(true); - this.color.setBlack(true); - this.color.setRed(true); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever an opponent loses life during your turn, you draw that many cards. - this.addAbility(new LoseLifeTriggeredAbility( - new DrawCardSourceControllerEffect(SavedLifeLossValue.MANY, true), - TargetController.OPPONENT, false, false - ).withTriggerCondition(MyTurnCondition.instance)); - } - - private KefkaRulerOfRuin(final KefkaRulerOfRuin card) { - super(card); - } - - @Override - public KefkaRulerOfRuin copy() { - return new KefkaRulerOfRuin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KessigForgemaster.java b/Mage.Sets/src/mage/cards/k/KessigForgemaster.java index 77c073320d1..1fbcff3d8d2 100644 --- a/Mage.Sets/src/mage/cards/k/KessigForgemaster.java +++ b/Mage.Sets/src/mage/cards/k/KessigForgemaster.java @@ -1,37 +1,48 @@ package mage.cards.k; -import mage.MageInt; import mage.abilities.common.BlocksOrBlockedByCreatureSourceTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; import java.util.UUID; /** * @author LevelX2 */ -public final class KessigForgemaster extends CardImpl { +public final class KessigForgemaster extends TransformingDoubleFacedCard { public KessigForgemaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); - this.subtype.add(SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{1}{R}", + "Flameheart Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.f.FlameheartWerewolf.class; + // Kessig Forgemaster + this.getLeftHalfCard().setPT(2, 1); // Whenever Kessig Forgemaster blocks or becomes blocked by a creature, Kessig Forgemaster deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.getLeftHalfCard().addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( + new DamageTargetEffect(1).withTargetDescription("that creature") + )); // At the beginning of each upkeep, if no spells were cast last turn, transform Kessig Forgemaster. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Flameheart Werewolf + this.getRightHalfCard().setPT(3, 2); + + // Whenever Flameheart Werewolf blocks or becomes blocked by a creature, Flameheart Werewolf deals 2 damage to that creature. + this.getRightHalfCard().addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( + new DamageTargetEffect(2).withTargetDescription("that creature") + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Flameheart Werewolf. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private KessigForgemaster(final KessigForgemaster card) { diff --git a/Mage.Sets/src/mage/cards/k/KessigNaturalist.java b/Mage.Sets/src/mage/cards/k/KessigNaturalist.java index 9fef85ab25d..6715ed7b487 100644 --- a/Mage.Sets/src/mage/cards/k/KessigNaturalist.java +++ b/Mage.Sets/src/mage/cards/k/KessigNaturalist.java @@ -1,16 +1,21 @@ package mage.cards.k; -import mage.MageInt; import mage.Mana; 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.BoostControlledEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; @@ -19,23 +24,45 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class KessigNaturalist extends CardImpl { +public final class KessigNaturalist extends TransformingDoubleFacedCard { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wolves and Werewolves"); + + static { + filter.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); + } public KessigNaturalist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{R}{G}", + "Lord of the Ulvenwald", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.l.LordOfTheUlvenwald.class; + // Kessig Naturalist + this.getLeftHalfCard().setPT(2, 2); // Whenever Kessig Naturalist attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end. - this.addAbility(new AttacksTriggeredAbility(new KessigNaturalistEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new KessigNaturalistEffect())); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Lord of the Ulvenwald + this.getRightHalfCard().setPT(3, 3); + + // Other Wolves and Werewolves you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + ))); + + // Whenever Lord of the Ulvenwald attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new KessigNaturalistEffect())); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private KessigNaturalist(final KessigNaturalist card) { diff --git a/Mage.Sets/src/mage/cards/k/KessigProwler.java b/Mage.Sets/src/mage/cards/k/KessigProwler.java index 0a0ddad939d..c04224886ec 100644 --- a/Mage.Sets/src/mage/cards/k/KessigProwler.java +++ b/Mage.Sets/src/mage/cards/k/KessigProwler.java @@ -1,36 +1,39 @@ - package mage.cards.k; -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.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.CantBeBlockedByMoreThanOneSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** * @author fireshoes */ -public final class KessigProwler extends CardImpl { +public final class KessigProwler extends TransformingDoubleFacedCard { public KessigProwler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{G}", + "Sinuous Predator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, ""); - this.secondSideCardClazz = mage.cards.s.SinuousPredator.class; + // Kessig Prowler + this.getLeftHalfCard().setPT(2, 1); // {4}{G}: Transform Kessig Prowler. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G}"))); + + // Sinuous Predator + this.getRightHalfCard().setPT(4, 4); + + // Sinuous Predator can't be blocked by more than one creature. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CantBeBlockedByMoreThanOneSourceEffect())); } private KessigProwler(final KessigProwler card) { diff --git a/Mage.Sets/src/mage/cards/k/KhenraSpellspear.java b/Mage.Sets/src/mage/cards/k/KhenraSpellspear.java index c7f6e66c63d..3edbc3a41f4 100644 --- a/Mage.Sets/src/mage/cards/k/KhenraSpellspear.java +++ b/Mage.Sets/src/mage/cards/k/KhenraSpellspear.java @@ -1,14 +1,13 @@ package mage.cards.k; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.ProwessAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.WardAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -17,26 +16,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class KhenraSpellspear extends CardImpl { +public final class KhenraSpellspear extends TransformingDoubleFacedCard { public KhenraSpellspear(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.JACKAL, SubType.WARRIOR}, "{1}{R}", + "Gitaxian Spellstalker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.JACKAL}, "UR"); - this.subtype.add(SubType.JACKAL); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.g.GitaxianSpellstalker.class; + // Khenra Spellspear + this.getLeftHalfCard().setPT(2, 2); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // Prowess - this.addAbility(new ProwessAbility()); + this.getLeftHalfCard().addAbility(new ProwessAbility()); // {3}{U/P}: Transform Khenra Spellspear. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{U/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{U/P}"))); + + // Gitaxian Spellstalker + this.getRightHalfCard().setPT(3, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Ward {2} + this.getRightHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + + // Prowess, Prowess + this.getRightHalfCard().addAbility(new ProwessAbility()); + this.getRightHalfCard().addAbility(new ProwessAbility()); } private KhenraSpellspear(final KhenraSpellspear card) { diff --git a/Mage.Sets/src/mage/cards/k/KindlyAncestor.java b/Mage.Sets/src/mage/cards/k/KindlyAncestor.java index a9b64514a7a..d1f923b021b 100644 --- a/Mage.Sets/src/mage/cards/k/KindlyAncestor.java +++ b/Mage.Sets/src/mage/cards/k/KindlyAncestor.java @@ -1,34 +1,54 @@ package mage.cards.k; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class KindlyAncestor extends CardImpl { +public final class KindlyAncestor extends TransformingDoubleFacedCard { public KindlyAncestor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{W}", + "Ancestor's Embrace", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.a.AncestorsEmbrace.class; + // Kindly Ancestor + this.getLeftHalfCard().setPT(2, 3); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Ancestor's Embrace + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {1}{W} - this.addAbility(new DisturbAbility(this, "{1}{W}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}")); + + // Enchanted creature has lifelink. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + ))); + + // If Ancestor's Embrace would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private KindlyAncestor(final KindlyAncestor card) { diff --git a/Mage.Sets/src/mage/cards/k/KindlyCustomer.java b/Mage.Sets/src/mage/cards/k/KindlyCustomer.java new file mode 100644 index 00000000000..20d5ed750ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindlyCustomer.java @@ -0,0 +1,38 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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 KindlyCustomer extends CardImpl { + + public KindlyCustomer(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 this creature enters, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + } + + private KindlyCustomer(final KindlyCustomer card) { + super(card); + } + + @Override + public KindlyCustomer copy() { + return new KindlyCustomer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KindlyStranger.java b/Mage.Sets/src/mage/cards/k/KindlyStranger.java index 8a07ada2da8..cf934f64ecf 100644 --- a/Mage.Sets/src/mage/cards/k/KindlyStranger.java +++ b/Mage.Sets/src/mage/cards/k/KindlyStranger.java @@ -1,38 +1,48 @@ package mage.cards.k; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; +import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author fireshoes */ -public final class KindlyStranger extends CardImpl { +public final class KindlyStranger extends TransformingDoubleFacedCard { public KindlyStranger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{2}{B}", + "Demon-Possessed Witch", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "B"); - this.secondSideCardClazz = mage.cards.d.DemonPossessedWitch.class; + // Kindly Stranger + this.getLeftHalfCard().setPT(2, 3); - // Delirium — {2}{B}: Transform Kindly Stranger. Activate this ability only if there are four or more card types among cards in your graveyard. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + // Delirium — {2}{B}: Transform Kindly Stranger. Activate only if there are four or more card types among cards in your graveyard. + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), DeliriumCondition.instance ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); + + // Demon-Possessed Witch + this.getRightHalfCard().setPT(4, 3); + + // When this creature transforms into Demon-Possessed Witch, you may destroy target creature. + Ability ability = new TransformIntoSourceTriggeredAbility(new DestroyTargetEffect(), true); + ability.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability); } private KindlyStranger(final KindlyStranger card) { diff --git a/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java b/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java deleted file mode 100644 index 254d48fc2e5..00000000000 --- a/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java +++ /dev/null @@ -1,137 +0,0 @@ -package mage.cards.k; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.Mode; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.cards.Card; -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.counters.CounterType; -import mage.filter.FilterCard; -import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.token.SpiritToken; -import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetControlledCreaturePermanent; - -/** - * - * @author weirddan455 - */ -public final class KirinTouchedOrochi extends CardImpl { - - private static final FilterCard filter = new FilterCard("noncreature card from a graveyard"); - static { - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - } - - public KirinTouchedOrochi(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SNAKE); - this.subtype.add(SubType.MONK); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Kirin-Touched Orochi attacks, choose one — - // • Exile target creature card from a graveyard. When you do, create a 1/1 colorless Spirit creature token. - Ability ability = new AttacksTriggeredAbility(new KirinTouchedOrochiTokenEffect()); - ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); - - // • Exile target noncreature card from a graveyard. When you do, put a +1/+1 counter on target creature you control. - Mode mode = new Mode(new KirinTouchedOrochiCounterEffect()); - mode.addTarget(new TargetCardInGraveyard(filter)); - ability.addMode(mode); - this.addAbility(ability); - } - - private KirinTouchedOrochi(final KirinTouchedOrochi card) { - super(card); - } - - @Override - public KirinTouchedOrochi copy() { - return new KirinTouchedOrochi(this); - } -} - -class KirinTouchedOrochiTokenEffect extends OneShotEffect { - - KirinTouchedOrochiTokenEffect() { - super(Outcome.Exile); - this.staticText = "Exile target creature card from a graveyard. When you do, create a 1/1 colorless Spirit creature token"; - } - - private KirinTouchedOrochiTokenEffect(final KirinTouchedOrochiTokenEffect effect) { - super(effect); - } - - @Override - public KirinTouchedOrochiTokenEffect copy() { - return new KirinTouchedOrochiTokenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - UUID targetId = source.getFirstTarget(); - Card card = game.getCard(targetId); - if (controller == null || card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { - return false; - } - if (!controller.moveCards(card, Zone.EXILED, source, game)) { - return false; - } - ReflexiveTriggeredAbility reflexiveTokenAbility = new ReflexiveTriggeredAbility(new CreateTokenEffect(new SpiritToken()), false); - game.fireReflexiveTriggeredAbility(reflexiveTokenAbility, source); - return true; - } -} - -class KirinTouchedOrochiCounterEffect extends OneShotEffect { - - KirinTouchedOrochiCounterEffect() { - super(Outcome.Exile); - this.staticText = "Exile target noncreature card from a graveyard. When you do, put a +1/+1 counter on target creature you control"; - } - - private KirinTouchedOrochiCounterEffect(final KirinTouchedOrochiCounterEffect effect) { - super(effect); - } - - @Override - public KirinTouchedOrochiCounterEffect copy() { - return new KirinTouchedOrochiCounterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - UUID targetId = source.getFirstTarget(); - Card card = game.getCard(targetId); - if (controller == null || card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { - return false; - } - if (!controller.moveCards(card, Zone.EXILED, source, game)) { - return false; - } - ReflexiveTriggeredAbility reflexiveCounterAbility = new ReflexiveTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); - reflexiveCounterAbility.addTarget(new TargetControlledCreaturePermanent()); - game.fireReflexiveTriggeredAbility(reflexiveCounterAbility, source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/k/KirolAttentiveFirstYear.java b/Mage.Sets/src/mage/cards/k/KirolAttentiveFirstYear.java new file mode 100644 index 00000000000..7d867994bc1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KirolAttentiveFirstYear.java @@ -0,0 +1,48 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.CopyTargetStackObjectEffect; +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.TargetStackObject; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KirolAttentiveFirstYear extends CardImpl { + + public KirolAttentiveFirstYear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R/W}{R/W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Tap two untapped creatures you control: Copy target triggered ability you control. You may choose new targets for the copy. Activate only once each turn. + Ability ability = new LimitedTimesPerTurnActivatedAbility( + new CopyTargetStackObjectEffect(), new TapTargetCost(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES) + ); + ability.addTarget(new TargetStackObject(StaticFilters.FILTER_CONTROLLED_TRIGGERED_ABILITY)); + this.addAbility(ability); + } + + private KirolAttentiveFirstYear(final KirolAttentiveFirstYear card) { + super(card); + } + + @Override + public KirolAttentiveFirstYear copy() { + return new KirolAttentiveFirstYear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java index 32b51409d80..fdfc2100202 100644 --- a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java +++ b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java @@ -30,13 +30,11 @@ import java.util.UUID; */ public final class KnollspineInvocation extends CardImpl { - protected static final FilterCard filter = new FilterCard("a card with mana value X"); - public KnollspineInvocation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); // {X}, Discard a card with mana value X: This enchantment deals X damage to any target. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance, true), new ManaCostsImpl<>("{X}")); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance), new ManaCostsImpl<>("{X}")); ability.addCost(new KnollspineInvocationDiscardCost()); ability.addTarget(new TargetAnyTarget()); ability.setCostAdjuster(KnollspineInvocationAdjuster.instance); diff --git a/Mage.Sets/src/mage/cards/k/KnowledgePool.java b/Mage.Sets/src/mage/cards/k/KnowledgePool.java index e553c7110c3..f7855166fc0 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgePool.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgePool.java @@ -1,5 +1,6 @@ package mage.cards.k; +import mage.ApprovingObject; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -26,7 +27,6 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author BetaSteward_at_googlemail.com @@ -181,7 +181,7 @@ class KnowledgePoolExileAndPlayEffect extends OneShotEffect { 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()); + TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileZoneId); target.withNotTarget(true); if (!spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, source, game)) { diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeSeeker.java b/Mage.Sets/src/mage/cards/k/KnowledgeSeeker.java new file mode 100644 index 00000000000..130bd0f3a19 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnowledgeSeeker.java @@ -0,0 +1,49 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +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.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnowledgeSeeker extends CardImpl { + + public KnowledgeSeeker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.FOX); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever you draw your second card each turn, put a +1/+1 counter on this creature. + this.addAbility(new DrawNthCardTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + + // When this creature dies, create a Clue token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + } + + private KnowledgeSeeker(final KnowledgeSeeker card) { + super(card); + } + + @Override + public KnowledgeSeeker copy() { + return new KnowledgeSeeker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KoalaSheep.java b/Mage.Sets/src/mage/cards/k/KoalaSheep.java new file mode 100644 index 00000000000..9d344c20698 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KoalaSheep.java @@ -0,0 +1,38 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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 KoalaSheep extends CardImpl { + + public KoalaSheep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.BEAR); + this.subtype.add(SubType.SHEEP); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When this creature enters, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + } + + private KoalaSheep(final KoalaSheep card) { + super(card); + } + + @Override + public KoalaSheep copy() { + return new KoalaSheep(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java b/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java new file mode 100644 index 00000000000..b40faff1f23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KohTheFaceStealer.java @@ -0,0 +1,167 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.cards.Card; +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.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +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.TargetCardInExile; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KohTheFaceStealer extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("another nontoken creature"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TokenPredicate.FALSE); + } + + public KohTheFaceStealer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHAPESHIFTER); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // When Koh enters, exile up to one other target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect()); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); + this.addAbility(ability); + + // Whenever another nontoken creature dies, you may exile it. + this.addAbility(new DiesCreatureTriggeredAbility( + new ExileTargetForSourceEffect().withTargetDescription("it"), true, filter, true + )); + + // Pay 1 life: Choose a creature card exiled with Koh. + this.addAbility(new SimpleActivatedAbility(new KohTheFaceStealerChooseEffect(), new PayLifeCost(1))); + + // Koh has all activated and triggered abilities of the last chosen card. + this.addAbility(new SimpleStaticAbility(new KohTheFaceStealerAbilityEffect())); + } + + private KohTheFaceStealer(final KohTheFaceStealer card) { + super(card); + } + + @Override + public KohTheFaceStealer copy() { + return new KohTheFaceStealer(this); + } +} + +class KohTheFaceStealerChooseEffect extends OneShotEffect { + + KohTheFaceStealerChooseEffect() { + super(Outcome.Benefit); + staticText = "choose a creature card exiled with {this}"; + } + + private KohTheFaceStealerChooseEffect(final KohTheFaceStealerChooseEffect effect) { + super(effect); + } + + @Override + public KohTheFaceStealerChooseEffect copy() { + return new KohTheFaceStealerChooseEffect(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; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + if (Optional + .ofNullable(game.getExile().getExileZone(exileId)) + .filter(HashSet::isEmpty) + .isPresent()) { + return false; + } + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD_CREATURE, exileId); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + game.getState().setValue( + CardUtil.getObjectZoneString( + "chosenCard", permanent.getId(), game, + permanent.getZoneChangeCounter(game), false + ), + new MageObjectReference(card, game) + ); + permanent.addInfo("chosen card", CardUtil.addToolTipMarkTags("Chosen Card " + card.getIdName()), game); + return true; + } +} + +class KohTheFaceStealerAbilityEffect extends ContinuousEffectImpl { + + KohTheFaceStealerAbilityEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.Benefit); + staticText = "{this} has all activated and triggered abilities of the last chosen card"; + } + + private KohTheFaceStealerAbilityEffect(final KohTheFaceStealerAbilityEffect effect) { + super(effect); + } + + @Override + public KohTheFaceStealerAbilityEffect copy() { + return new KohTheFaceStealerAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + Card card = Optional + .ofNullable(CardUtil.getCardZoneString("chosenCard", source.getSourceId(), game, false)) + .map(game.getState()::getValue) + .map(MageObjectReference.class::cast) + .map(mor -> mor.getCard(game)) + .orElse(null); + if (permanent == null || card == null) { + return false; + } + for (Ability ability : card.getAbilities(game)) { + if (ability.isActivatedAbility() || ability.isTriggeredAbility()) { + permanent.addAbility(ability, source.getSourceId(), game, true); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java b/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java index c0fb8e3cf9c..aeac9a73ecd 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanAspirant.java @@ -24,7 +24,7 @@ public final class KolaghanAspirant extends CardImpl { this.toughness = new MageInt(1); // Whenever Kolaghan Aspirant becomes blocked by a creature, Kolaghan Aspirant deals 1 damage to that creature. - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1, true, "that creature"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"), false)); } private KolaghanAspirant(final KolaghanAspirant card) { diff --git a/Mage.Sets/src/mage/cards/k/KorvoldFaeCursedKing.java b/Mage.Sets/src/mage/cards/k/KorvoldFaeCursedKing.java index f2fd40b4b93..d3771655893 100644 --- a/Mage.Sets/src/mage/cards/k/KorvoldFaeCursedKing.java +++ b/Mage.Sets/src/mage/cards/k/KorvoldFaeCursedKing.java @@ -14,9 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; @@ -25,12 +23,6 @@ import java.util.UUID; */ public final class KorvoldFaeCursedKing extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public KorvoldFaeCursedKing(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}{G}"); @@ -45,13 +37,14 @@ public final class KorvoldFaeCursedKing extends CardImpl { // Whenever Korvold, Fae-Cursed King enters the battlefield or attacks, sacrifice another permanent. this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( - new SacrificeControllerEffect(filter, 1, "") + new SacrificeControllerEffect(StaticFilters.FILTER_ANOTHER_PERMANENT, 1, "") )); // Whenever you sacrifice a permanent, put a +1/+1 counter on Korvold and draw a card. Ability ability = new SacrificePermanentTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - StaticFilters.FILTER_PERMANENT); + StaticFilters.FILTER_PERMANENT + ); ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java b/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java index 82dbe08f976..01280ba2caa 100644 --- a/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java +++ b/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java @@ -29,8 +29,8 @@ import java.util.UUID; */ public final class KothOfTheHammer extends CardImpl { - static final FilterPermanent filter = new FilterPermanent(SubType.MOUNTAIN, "Mountain"); - static final FilterPermanent filterCount = new FilterControlledPermanent("Mountain you control"); + private static final FilterPermanent filter = new FilterPermanent(SubType.MOUNTAIN, "Mountain"); + private static final FilterPermanent filterCount = new FilterControlledPermanent(SubType.MOUNTAIN, "Mountain you control"); public KothOfTheHammer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); diff --git a/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java b/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java deleted file mode 100644 index c57d2e864bb..00000000000 --- a/Mage.Sets/src/mage/cards/k/KrallenhordeHowler.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -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 java.util.UUID; - -/** - * @author fireshoes - */ -public final class KrallenhordeHowler extends CardImpl { - - private static final FilterCard FILTER = new FilterCreatureCard("creature spells"); - - public KrallenhordeHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Creature spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(FILTER, 1))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Howler. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private KrallenhordeHowler(final KrallenhordeHowler card) { - super(card); - } - - @Override - public KrallenhordeHowler copy() { - return new KrallenhordeHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KrallenhordeKiller.java b/Mage.Sets/src/mage/cards/k/KrallenhordeKiller.java deleted file mode 100644 index 5c2fc9960cc..00000000000 --- a/Mage.Sets/src/mage/cards/k/KrallenhordeKiller.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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.Duration; -import mage.constants.SubType; -import mage.constants.Zone; - -import java.util.UUID; - -/** - * @author Loki - */ -public final class KrallenhordeKiller extends CardImpl { - - public KrallenhordeKiller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - this.nightCard = true; - - // {3}{G}: Krallenhorde Killer gets +4/+4 until end of turn. Activate this ability only once each turn. - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(4, 4, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{G}"))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Killer. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private KrallenhordeKiller(final KrallenhordeKiller card) { - super(card); - } - - @Override - public KrallenhordeKiller copy() { - return new KrallenhordeKiller(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KrallenhordeWantons.java b/Mage.Sets/src/mage/cards/k/KrallenhordeWantons.java deleted file mode 100644 index dc8e2624601..00000000000 --- a/Mage.Sets/src/mage/cards/k/KrallenhordeWantons.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class KrallenhordeWantons extends CardImpl { - - public KrallenhordeWantons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(7); - this.toughness = new MageInt(7); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Wantons. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private KrallenhordeWantons(final KrallenhordeWantons card) { - super(card); - } - - @Override - public KrallenhordeWantons copy() { - return new KrallenhordeWantons(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KrangMasterMind.java b/Mage.Sets/src/mage/cards/k/KrangMasterMind.java new file mode 100644 index 00000000000..337b666365c --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KrangMasterMind.java @@ -0,0 +1,67 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DrawCardsEqualToDifferenceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KrangMasterMind extends CardImpl { + + private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 4); + private static final FilterPermanent filter = new FilterControlledArtifactPermanent("other artifact you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + public KrangMasterMind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.UTROM); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // When Krang enters, if you have fewer than four cards in hand, draw cards equal to the difference. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardsEqualToDifferenceEffect(4)) + .withInterveningIf(condition)); + + // Krang gets +1/+0 for each other artifact you control. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + xValue, StaticValue.get(0), Duration.WhileOnBattlefield + ))); + } + + private KrangMasterMind(final KrangMasterMind card) { + super(card); + } + + @Override + public KrangMasterMind copy() { + return new KrangMasterMind(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KratosGodOfWar.java b/Mage.Sets/src/mage/cards/k/KratosGodOfWar.java index bb8044ebe62..3fdb3222483 100644 --- a/Mage.Sets/src/mage/cards/k/KratosGodOfWar.java +++ b/Mage.Sets/src/mage/cards/k/KratosGodOfWar.java @@ -39,10 +39,13 @@ public final class KratosGodOfWar extends CardImpl { this.addAbility(DoubleStrikeAbility.getInstance()); // All creatures have haste. - this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( - HasteAbility.getInstance(), Duration.WhileControlled, - StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("all creatures have haste"))); + this.addAbility( + new SimpleStaticAbility( + new GainAbilityAllEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ).setText("all creatures have haste") + )); // At the beginning of each player's end step, Kratos deals damage to that player equal to the number of creatures that player controls that didn't attack this turn. this.addAbility(new BeginningOfEndStepTriggeredAbility( @@ -89,7 +92,7 @@ class KratosGodOfWarEffect extends OneShotEffect { if (player == null) { return false; } - int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); + int count = game.getBattlefield().count(filter, game.getActivePlayerId(), source, game); return count > 0 && player.damage(count, source, game) > 0; } } diff --git a/Mage.Sets/src/mage/cards/k/KratosStoicFather.java b/Mage.Sets/src/mage/cards/k/KratosStoicFather.java new file mode 100644 index 00000000000..ede9a3f28c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KratosStoicFather.java @@ -0,0 +1,69 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersControllerCount; +import mage.abilities.effects.common.counter.AddCountersPlayersEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.meta.OrTriggeredAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KratosStoicFather extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GOD); + private static final DynamicValue xValue = new CountersControllerCount(CounterType.EXPERIENCE); + + public KratosStoicFather(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.GOD); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever you attack with one or more Gods and whenever a God dies, you get an experience counter. + this.addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, + new AddCountersPlayersEffect(CounterType.EXPERIENCE.createInstance(), TargetController.YOU), + new AttacksWithCreaturesTriggeredAbility(null, 1, filter), + new DiesCreatureTriggeredAbility(null, false, filter) + ).setTriggerPhrase("Whenever you attack with one or more Gods and whenever a God dies, ")); + + // At the beginning of your end step, put a number of +1/+1 counters on target creature equal to the number of experience counters you have. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(), xValue) + .setText("put a number of +1/+1 counters on target creature " + + "equal to the number of experience counters you have") + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Partner--Father & son + this.addAbility(PartnerVariantType.FATHER_AND_SON.makeAbility()); + } + + private KratosStoicFather(final KratosStoicFather card) { + super(card); + } + + @Override + public KratosStoicFather copy() { + return new KratosStoicFather(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KrothussLordOfTheDeep.java b/Mage.Sets/src/mage/cards/k/KrothussLordOfTheDeep.java deleted file mode 100644 index d58282aa09e..00000000000 --- a/Mage.Sets/src/mage/cards/k/KrothussLordOfTheDeep.java +++ /dev/null @@ -1,98 +0,0 @@ -package mage.cards.k; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenCopyTargetEffect; -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.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterAttackingCreature; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class KrothussLordOfTheDeep extends CardImpl { - - private static final FilterPermanent filter = new FilterAttackingCreature("another attacking creature"); - - static { - filter.add(AnotherPredicate.instance); - } - - public KrothussLordOfTheDeep(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.KRAKEN); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Krothuss, Lord of the Deep attacks, create a tapped and attacking token that's a copy of another target attacking creature. If that creature is a Kraken, Leviathan, Octopus, or Serpent, create two of those tokens instead. - Ability ability = new AttacksTriggeredAbility(new KrothussLordOfTheDeepEffect()); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - } - - private KrothussLordOfTheDeep(final KrothussLordOfTheDeep card) { - super(card); - } - - @Override - public KrothussLordOfTheDeep copy() { - return new KrothussLordOfTheDeep(this); - } -} - -class KrothussLordOfTheDeepEffect extends OneShotEffect { - - KrothussLordOfTheDeepEffect() { - super(Outcome.Benefit); - staticText = "create a tapped and attacking token that's a copy of another target attacking creature. " + - "If that creature is a Kraken, Leviathan, Octopus, or Serpent, create two of those tokens instead"; - } - - private KrothussLordOfTheDeepEffect(final KrothussLordOfTheDeepEffect effect) { - super(effect); - } - - @Override - public KrothussLordOfTheDeepEffect copy() { - return new KrothussLordOfTheDeepEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - return false; - } - int count = permanent.hasSubtype(SubType.KRAKEN, game) - || permanent.hasSubtype(SubType.LEVIATHAN, game) - || permanent.hasSubtype(SubType.OCTOPUS, game) - || permanent.hasSubtype(SubType.SERPENT, game) ? 2 : 1; - return new CreateTokenCopyTargetEffect( - null, null, - false, count, true, true - ).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KruinOutlaw.java b/Mage.Sets/src/mage/cards/k/KruinOutlaw.java index 71b48621976..73705a0f0b0 100644 --- a/Mage.Sets/src/mage/cards/k/KruinOutlaw.java +++ b/Mage.Sets/src/mage/cards/k/KruinOutlaw.java @@ -1,36 +1,56 @@ package mage.cards.k; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; import java.util.UUID; /** * @author North */ -public final class KruinOutlaw extends CardImpl { +public final class KruinOutlaw extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent(SubType.WEREWOLF, "Werewolves"); public KruinOutlaw(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{1}{R}{R}", + "Terror of Kruin Pass", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R"); - this.secondSideCardClazz = mage.cards.t.TerrorOfKruinPass.class; + // Kruin Outlaw + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + // First strike + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); - this.addAbility(FirstStrikeAbility.getInstance()); // At the beginning of each upkeep, if no spells were cast last turn, transform Kruin Outlaw. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Terror of Kruin Pass + this.getRightHalfCard().setPT(3, 3); + + // Double strike + this.getRightHalfCard().addAbility(DoubleStrikeAbility.getInstance()); + + // Werewolves you control have menace. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(), Duration.WhileOnBattlefield, filter, false + ))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Terror of Kruin Pass. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private KruinOutlaw(final KruinOutlaw card) { diff --git a/Mage.Sets/src/mage/cards/k/KujaGenomeSorcerer.java b/Mage.Sets/src/mage/cards/k/KujaGenomeSorcerer.java index 6784c390e47..6abd2425003 100644 --- a/Mage.Sets/src/mage/cards/k/KujaGenomeSorcerer.java +++ b/Mage.Sets/src/mage/cards/k/KujaGenomeSorcerer.java @@ -1,48 +1,46 @@ 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.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.constants.ComparisonType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.token.BlackWizardToken; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; /** * @author balazskristof */ -public final class KujaGenomeSorcerer extends CardImpl { +public final class KujaGenomeSorcerer extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.WIZARD); private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.OR_GREATER, 4); private static final Hint hint = new ValueHint("Wizards you control", new PermanentsOnBattlefieldCount(filter)); public KujaGenomeSorcerer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MUTANT); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MUTANT, SubType.WIZARD}, "{2}{B}{R}", + "Trance Kuja, Fate Defied", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.WIZARD}, "BR"); - this.secondSideCardClazz = mage.cards.t.TranceKujaFateDefied.class; + // Kuja, Genome Sorcerer + this.getLeftHalfCard().setPT(3, 4); // At the beginning of your end step, create a tapped 0/1 black Wizard creature token with "Whenever you cast a noncreature spell, this token deals 1 damage to each opponent.", Then if you control four or more Wizards, transform Kuja. Ability ability = new BeginningOfEndStepTriggeredAbility( @@ -54,8 +52,13 @@ public final class KujaGenomeSorcerer extends CardImpl { "if you control four or more Wizards, transform {this}" ).concatBy("Then")); ability.addHint(hint); - this.addAbility(ability); - this.addAbility(new TransformAbility()); + this.getLeftHalfCard().addAbility(ability); + + // Trance Kuja, Fate Defied + this.getRightHalfCard().setPT(4, 6); + + // Flame Star -- If a Wizard you control would deal damage to a permanent or player, it deals double that damage instead. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new TranceKujaFateDefiedEffect()).withFlavorWord("Flare Star")); } private KujaGenomeSorcerer(final KujaGenomeSorcerer card) { @@ -67,3 +70,40 @@ public final class KujaGenomeSorcerer extends CardImpl { return new KujaGenomeSorcerer(this); } } + +class TranceKujaFateDefiedEffect extends ReplacementEffectImpl { + + TranceKujaFateDefiedEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + staticText = "If a Wizard you control would deal damage to a permanent or player, it deals double that damage instead."; + } + + private TranceKujaFateDefiedEffect(final TranceKujaFateDefiedEffect effect) { + super(effect); + } + + @Override + public TranceKujaFateDefiedEffect copy() { + return new TranceKujaFateDefiedEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType().equals(GameEvent.EventType.DAMAGE_PLAYER) + || event.getType().equals(GameEvent.EventType.DAMAGE_PERMANENT); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return game.getControllerId(event.getSourceId()).equals(source.getControllerId()) + && Optional.ofNullable(game.getObject(event.getSourceId())) + .map(object -> object.hasSubtype(SubType.WIZARD, game)) + .orElse(false); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2)); + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java index b5008af8aa6..3bb5fe4b68f 100644 --- a/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java +++ b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java @@ -1,27 +1,31 @@ package mage.cards.k; +import mage.abilities.Ability; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.AddCounterNextSpellDelayedTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.HasteAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.watchers.common.DamagedByControlledWatcher; import java.util.UUID; /** * @author weirddan455 */ -public final class KumanoFacesKakkazan extends CardImpl { +public final class KumanoFacesKakkazan extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterPlaneswalkerPermanent(); @@ -30,31 +34,42 @@ 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; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{R}", + "Etching of Kumano", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "R"); + // Kumano Faces Kakkazan // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Kumano Faces Kakkazan deals 1 damage to each opponent and each planeswalker they control. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new DamagePlayersEffect(1, TargetController.OPPONENT), new DamageAllEffect(1, filter).setText("and each planeswalker they control") ); // 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, + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new CreateDelayedTriggeredAbilityEffect(new AddCounterNextSpellDelayedTriggeredAbility()) ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Etching of Kumano + this.getRightHalfCard().setPT(2, 2); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // If a creature dealt damage this turn by a source you controlled would die, exile it instead. + Ability ability = new SimpleStaticAbility(new EtchingOfKumanoReplacementEffect()); + ability.addWatcher(new DamagedByControlledWatcher()); + this.getRightHalfCard().addAbility(ability); } private KumanoFacesKakkazan(final KumanoFacesKakkazan card) { @@ -66,3 +81,43 @@ public final class KumanoFacesKakkazan extends CardImpl { return new KumanoFacesKakkazan(this); } } + +class EtchingOfKumanoReplacementEffect extends ReplacementEffectImpl { + + 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/k/KutzilsFlanker.java b/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java index 79ecf0f0963..f9f53fe1a50 100644 --- a/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java +++ b/Mage.Sets/src/mage/cards/k/KutzilsFlanker.java @@ -10,24 +10,18 @@ import mage.abilities.effects.common.ExileGraveyardAllTargetPlayerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlashAbility; 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.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.target.TargetPlayer; -import mage.util.CardUtil; -import mage.watchers.Watcher; +import mage.watchers.common.CreatureLeftBattlefieldWatcher; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; /** @@ -52,8 +46,8 @@ public final class KutzilsFlanker extends CardImpl { new AddCountersSourceEffect(CounterType.P1P1.createInstance(), KutzilsFlankerValue.instance, true) .setText("put a +1/+1 counter on {this} for each creature that left the battlefield under your control this turn") ); - ability.addHint(new ValueHint("Number of creatures that left", KutzilsFlankerValue.instance)); - ability.addWatcher(new KutzilsFlankerWatcher()); + ability.addHint(KutzilsFlankerValue.getHint()); + ability.addWatcher(new CreatureLeftBattlefieldWatcher()); // * You gain 2 life and scry 2. ability.addMode(new Mode( @@ -82,10 +76,15 @@ public final class KutzilsFlanker extends CardImpl { enum KutzilsFlankerValue implements DynamicValue { instance; + private static final Hint hint = new ValueHint("Number of creatures that left", KutzilsFlankerValue.instance); + + public static Hint getHint() { + return hint; + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return KutzilsFlankerWatcher.getNumberCreatureLeft(sourceAbility.getControllerId(), game); + return CreatureLeftBattlefieldWatcher.getNumberCreatureLeft(sourceAbility.getControllerId(), game); } @Override @@ -103,37 +102,3 @@ enum KutzilsFlankerValue implements DynamicValue { return ""; } } - - -class KutzilsFlankerWatcher extends Watcher { - - // player -> number of creatures that left the battlefield under that player's control this turn - private final Map mapCreaturesLeft = new HashMap<>(); - - KutzilsFlankerWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { - return; - } - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() != Zone.BATTLEFIELD || !zEvent.getTarget().isCreature(game)) { - return; - } - mapCreaturesLeft.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue); - } - - @Override - public void reset() { - super.reset(); - mapCreaturesLeft.clear(); - } - - public static int getNumberCreatureLeft(UUID playerId, Game game) { - KutzilsFlankerWatcher watcher = game.getState().getWatcher(KutzilsFlankerWatcher.class); - return watcher == null ? 0 : watcher.mapCreaturesLeft.getOrDefault(playerId, 0); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KyoshiBattleFan.java b/Mage.Sets/src/mage/cards/k/KyoshiBattleFan.java new file mode 100644 index 00000000000..624d4a13c56 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyoshiBattleFan.java @@ -0,0 +1,44 @@ +package mage.cards.k; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenAttachSourceEffect; +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.SubType; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KyoshiBattleFan extends CardImpl { + + public KyoshiBattleFan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When this Equipment enters, create a 1/1 white Ally creature token, then attach this Equipment to it. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenAttachSourceEffect(new AllyToken()))); + + // Equipped creature gets +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private KyoshiBattleFan(final KyoshiBattleFan card) { + super(card); + } + + @Override + public KyoshiBattleFan copy() { + return new KyoshiBattleFan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KyoshiIslandPlaza.java b/Mage.Sets/src/mage/cards/k/KyoshiIslandPlaza.java new file mode 100644 index 00000000000..6bfd4c5fe3c --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyoshiIslandPlaza.java @@ -0,0 +1,76 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +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.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KyoshiIslandPlaza extends CardImpl { + + public KyoshiIslandPlaza(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // When Kyoshi Island Plaza enters, search your library for up to X basic land cards, where X is the number of Shrines you control. Put those cards onto the battlefield tapped, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new KyoshiIslandPlazaEffect()) + .addHint(ShrinesYouControlCount.getHint())); + + // Whenever another Shrine you control enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ), StaticFilters.FILTER_ANOTHER_CONTROLLED_SHRINE)); + } + + private KyoshiIslandPlaza(final KyoshiIslandPlaza card) { + super(card); + } + + @Override + public KyoshiIslandPlaza copy() { + return new KyoshiIslandPlaza(this); + } +} + +class KyoshiIslandPlazaEffect extends OneShotEffect { + + KyoshiIslandPlazaEffect() { + super(Outcome.Benefit); + staticText = "search your library for up to X basic land cards, where X is the number of Shrines you control. " + + "Put those cards onto the battlefield tapped, then shuffle"; + } + + private KyoshiIslandPlazaEffect(final KyoshiIslandPlazaEffect effect) { + super(effect); + } + + @Override + public KyoshiIslandPlazaEffect copy() { + return new KyoshiIslandPlazaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int count = ShrinesYouControlCount.WHERE_X.calculate(game, source, this); + return new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(0, count, StaticFilters.FILTER_CARD_BASIC_LANDS), true + ).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KyoshiVillage.java b/Mage.Sets/src/mage/cards/k/KyoshiVillage.java new file mode 100644 index 00000000000..b81da4ec485 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyoshiVillage.java @@ -0,0 +1,48 @@ +package mage.cards.k; + +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.GenericManaCost; +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 KyoshiVillage extends CardImpl { + + public KyoshiVillage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {G} or {W}. + this.addAbility(new GreenManaAbility()); + this.addAbility(new WhiteManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private KyoshiVillage(final KyoshiVillage card) { + super(card); + } + + @Override + public KyoshiVillage copy() { + return new KyoshiVillage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KyoshiWarriorExemplars.java b/Mage.Sets/src/mage/cards/k/KyoshiWarriorExemplars.java new file mode 100644 index 00000000000..f6c4da33ceb --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyoshiWarriorExemplars.java @@ -0,0 +1,51 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.hint.common.LandsYouControlHint; +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.common.FilterControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KyoshiWarriorExemplars extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledLandPermanent("you control eight or more lands"), ComparisonType.MORE_THAN, 7 + ); + + public KyoshiWarriorExemplars(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Whenever this creature attacks, if you control eight or more lands, creatures you control get +2/+2 until end of turn. + this.addAbility(new AttacksTriggeredAbility( + new BoostControlledEffect(2, 2, Duration.EndOfTurn) + ).withInterveningIf(condition).addHint(LandsYouControlHint.instance)); + } + + private KyoshiWarriorExemplars(final KyoshiWarriorExemplars card) { + super(card); + } + + @Override + public KyoshiWarriorExemplars copy() { + return new KyoshiWarriorExemplars(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KyoshiWarriors.java b/Mage.Sets/src/mage/cards/k/KyoshiWarriors.java new file mode 100644 index 00000000000..979844a52c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyoshiWarriors.java @@ -0,0 +1,40 @@ +package mage.cards.k; + +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.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KyoshiWarriors extends CardImpl { + + public KyoshiWarriors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, create a 1/1 white Ally creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new AllyToken()))); + } + + private KyoshiWarriors(final KyoshiWarriors card) { + super(card); + } + + @Override + public KyoshiWarriors copy() { + return new KyoshiWarriors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KyrenFlamewright.java b/Mage.Sets/src/mage/cards/k/KyrenFlamewright.java deleted file mode 100644 index a0e95b8626e..00000000000 --- a/Mage.Sets/src/mage/cards/k/KyrenFlamewright.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.k; - -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.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -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.filter.StaticFilters; -import mage.game.permanent.token.Elemental11BlueRedToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class KyrenFlamewright extends CardImpl { - - public KyrenFlamewright(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOBLIN); - this.subtype.add(SubType.SPELLSHAPER); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // {2}{R}, {T}, Discard a card: Create two 1/1 blue and red Elemental creature tokens. Creatures you control get +1/+0 and gain haste until end of turn. - Ability ability = new SimpleActivatedAbility( - new CreateTokenEffect(new Elemental11BlueRedToken(), 2), new ManaCostsImpl<>("{2}{R}") - ); - ability.addCost(new TapSourceCost()); - ability.addCost(new DiscardCardCost()); - ability.addEffect(new BoostControlledEffect(1, 0, Duration.EndOfTurn) - .setText("creatures you control get +1/+0")); - ability.addEffect(new GainAbilityControlledEffect( - HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES - ).setText("and gain haste until end of turn")); - this.addAbility(ability); - } - - private KyrenFlamewright(final KyrenFlamewright card) { - super(card); - } - - @Override - public KyrenFlamewright copy() { - return new KyrenFlamewright(this); - } -} diff --git a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java index 56c4872994e..44418fa3597 100644 --- a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java +++ b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java @@ -1,19 +1,27 @@ package mage.cards.k; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.EndOfCombatTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import mage.watchers.common.AttackedOrBlockedThisCombatWatcher; import java.util.UUID; @@ -21,30 +29,53 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class KytheonHeroOfAkros extends CardImpl { +public final class KytheonHeroOfAkros extends TransformingDoubleFacedCard { public KytheonHeroOfAkros(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{W}", + "Gideon, Battle-Forged", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.GIDEON}, "W"); - this.secondSideCardClazz = mage.cards.g.GideonBattleForged.class; + // Kytheon, Hero of Akros + this.getLeftHalfCard().setPT(2, 1); - // At end of combat, if Kytheon, Hero of Akros and at least two other creatures attacked this combat, exile Kytheon, - // then return him to the battlefield transformed under his owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new EndOfCombatTriggeredAbility( + // At end of combat, if Kytheon, Hero of Akros and at least two other creatures attacked this combat, exile Kytheon, then return him to the battlefield transformed under his owner's control. + Ability kytheonAbility = new EndOfCombatTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), false - ).withInterveningIf(KytheonHeroOfAkrosCondition.instance), new AttackedOrBlockedThisCombatWatcher()); + ).withInterveningIf(KytheonHeroOfAkrosCondition.instance); + kytheonAbility.addWatcher(new AttackedOrBlockedThisCombatWatcher()); + this.getLeftHalfCard().addAbility(kytheonAbility); // {2}{W}: Kytheon gains indestructible until end of turn. - this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn ), new ManaCostsImpl<>("{2}{W}"))); + // Gideon, Battle-Forged + this.getRightHalfCard().setStartingLoyalty(3); + + // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. + Ability ability = new LoyaltyAbility(new GideonBattleForgedEffect(), 2); + ability.addTarget(new TargetOpponentsCreaturePermanent(0, 1)); + this.getRightHalfCard().addAbility(ability); + + // +1: Until your next turn, target creature gains indestructible. Untap that creature. + ability = new LoyaltyAbility(new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("Until your next turn, target creature gains indestructible"), 1); + ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); + ability.addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().addAbility(ability); + + // 0: Until end of turn, Gideon, Battle-Forged becomes a 4/4 Human Soldier creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn. + ability = new LoyaltyAbility(new BecomesCreatureSourceEffect(new CreatureToken( + 4, 4, "4/4 Human Soldier creature " + + "with indestructible", SubType.HUMAN, SubType.SOLDIER + ).withAbility(IndestructibleAbility.getInstance()), CardType.PLANESWALKER, Duration.EndOfTurn), 0); + ability.addEffect(new PreventAllDamageToSourceEffect(Duration.EndOfTurn) + .setText("Prevent all damage that would be dealt to him this turn")); + this.getRightHalfCard().addAbility(ability); } private KytheonHeroOfAkros(final KytheonHeroOfAkros card) { @@ -78,3 +109,74 @@ enum KytheonHeroOfAkrosCondition implements Condition { return "if {this} and at least two other creatures attacked this combat"; } } + +class GideonBattleForgedEffect extends RequirementEffect { + + protected mage.MageObjectReference targetPermanentReference; + + GideonBattleForgedEffect() { + super(Duration.Custom); + staticText = "up to one target creature an opponent controls attacks {this} during its controller's next turn if able"; + } + + private GideonBattleForgedEffect(final GideonBattleForgedEffect effect) { + super(effect); + this.targetPermanentReference = effect.targetPermanentReference; + } + + @Override + public GideonBattleForgedEffect copy() { + return new GideonBattleForgedEffect(this); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (targetPermanentReference == null) { + return true; + } + Permanent targetPermanent = targetPermanentReference.getPermanent(game); + if (targetPermanent == null) { + return true; + } + return game.getTurnPhaseType() == TurnPhase.END && this.isYourNextTurn(game); // discard on end of their next turn + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (getTargetPointer().getFirst(game, source) == null) { + discard(); + } else { + targetPermanentReference = new mage.MageObjectReference(getTargetPointer().getFirst(game, source), game); + } + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (!permanent.getId().equals(getTargetPointer().getFirst(game, source)) + || !game.isActivePlayer(permanent.getControllerId())) { + return false; + } + Permanent planeswalker = source.getSourcePermanentIfItStillExists(game); + if (planeswalker == null) { + discard(); + return false; + } + return true; + } + + @Override + public UUID mustAttackDefender(Ability source, Game game) { + return source.getSourceId(); + } + + @Override + public boolean mustAttack(Game game) { + return true; + } + + @Override + public boolean mustBlock(Game game) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LambholtButcher.java b/Mage.Sets/src/mage/cards/l/LambholtButcher.java deleted file mode 100644 index 7e168fbffb3..00000000000 --- a/Mage.Sets/src/mage/cards/l/LambholtButcher.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class LambholtButcher extends CardImpl { - - public LambholtButcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private LambholtButcher(final LambholtButcher card) { - super(card); - } - - @Override - public LambholtButcher copy() { - return new LambholtButcher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LambholtElder.java b/Mage.Sets/src/mage/cards/l/LambholtElder.java index 9706367e69e..205a4edfa76 100644 --- a/Mage.Sets/src/mage/cards/l/LambholtElder.java +++ b/Mage.Sets/src/mage/cards/l/LambholtElder.java @@ -1,10 +1,11 @@ package mage.cards.l; -import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,21 +14,31 @@ import java.util.UUID; /** * @author Loki */ -public final class LambholtElder extends CardImpl { +public final class LambholtElder extends TransformingDoubleFacedCard { public LambholtElder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{G}", + "Silverpelt Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.s.SilverpeltWerewolf.class; + // Lambholt Elder + this.getLeftHalfCard().setPT(1, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Lambholt Elder. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Silverpelt Werewolf + this.getRightHalfCard().setPT(4, 5); + + // Whenever Silverpelt Werewolf deals combat damage to a player, draw a card. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Silverpelt Werewolf. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private LambholtElder(final LambholtElder card) { diff --git a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java index 36969373dc5..ab4f81c39fa 100644 --- a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java +++ b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java @@ -1,7 +1,7 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; @@ -9,9 +9,8 @@ import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.combat.CantAttackSourceEffect; import mage.abilities.hint.common.FerociousHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -21,29 +20,32 @@ import java.util.UUID; /** * @author fireshoes */ -public final class LambholtPacifist extends CardImpl { +public final class LambholtPacifist extends TransformingDoubleFacedCard { private static final Condition condition = new InvertCondition(FerociousCondition.instance); public LambholtPacifist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{1}{G}", + "Lambholt Butcher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.secondSideCardClazz = mage.cards.l.LambholtButcher.class; + this.getLeftHalfCard().setPT(3, 3); + this.getRightHalfCard().setPT(4, 4); // Lambholt Pacifist can't attack unless you control a creature with power 4 or greater. - this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( new CantAttackSourceEffect(Duration.WhileOnBattlefield), condition, "{this} can't attack unless you control a creature with power 4 or greater" )).addHint(FerociousHint.instance)); // At the beginning of each upkeep, if no spells were cast last turn, transform Lambholt Pacifist. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Lambholt Butcher + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private LambholtPacifist(final LambholtPacifist card) { diff --git a/Mage.Sets/src/mage/cards/l/LambholtRaconteur.java b/Mage.Sets/src/mage/cards/l/LambholtRaconteur.java index 8c0b060799b..fa26a1a5e3b 100644 --- a/Mage.Sets/src/mage/cards/l/LambholtRaconteur.java +++ b/Mage.Sets/src/mage/cards/l/LambholtRaconteur.java @@ -1,11 +1,11 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; @@ -16,25 +16,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LambholtRaconteur extends CardImpl { +public final class LambholtRaconteur extends TransformingDoubleFacedCard { public LambholtRaconteur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Lambholt Ravager", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.l.LambholtRavager.class; + // Lambholt Raconteur + this.getLeftHalfCard().setPT(2, 4); // Whenever you cast a noncreature spell, Lambholt Raconteur deals 1 damage to each opponent. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( new DamagePlayersEffect(1, TargetController.OPPONENT), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Lambholt Ravager + this.getRightHalfCard().setPT(4, 4); + + // Whenever you cast a noncreature spell, Lambholt Ravager deals 2 damage to each opponent. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new DamagePlayersEffect(2, TargetController.OPPONENT), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private LambholtRaconteur(final LambholtRaconteur card) { diff --git a/Mage.Sets/src/mage/cards/l/LambholtRavager.java b/Mage.Sets/src/mage/cards/l/LambholtRavager.java deleted file mode 100644 index 36eabbf2986..00000000000 --- a/Mage.Sets/src/mage/cards/l/LambholtRavager.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.keyword.NightboundAbility; -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 LambholtRavager extends CardImpl { - - public LambholtRavager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Whenever you cast a noncreature spell, Lambholt Ravager deals 2 damage to each opponent. - this.addAbility(new SpellCastControllerTriggeredAbility( - new DamagePlayersEffect(2, TargetController.OPPONENT), - StaticFilters.FILTER_SPELL_A_NON_CREATURE, false - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private LambholtRavager(final LambholtRavager card) { - super(card); - } - - @Override - public LambholtRavager copy() { - return new LambholtRavager(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LanternBearer.java b/Mage.Sets/src/mage/cards/l/LanternBearer.java index 4f44b1d854d..632d677f587 100644 --- a/Mage.Sets/src/mage/cards/l/LanternBearer.java +++ b/Mage.Sets/src/mage/cards/l/LanternBearer.java @@ -1,34 +1,61 @@ package mage.cards.l; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class LanternBearer extends CardImpl { +public final class LanternBearer extends TransformingDoubleFacedCard { public LanternBearer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{U}", + "Lanterns' Lift", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U" + ); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.l.LanternsLift.class; + // Lantern Bearer + this.getLeftHalfCard().setPT(1, 1); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); + + // Lanterns' Lift + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {2}{U} - this.addAbility(new DisturbAbility(this, "{2}{U}")); + // needs to be added after right half has spell ability target set + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{U}")); + + // Enchanted creature gets +1/+1 and has flying. + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 1, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.getRightHalfCard().addAbility(ability); + + // If Lanterns' Lift would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private LanternBearer(final LanternBearer card) { diff --git a/Mage.Sets/src/mage/cards/l/LavabornMuse.java b/Mage.Sets/src/mage/cards/l/LavabornMuse.java index e63bccc138b..7c215610f31 100644 --- a/Mage.Sets/src/mage/cards/l/LavabornMuse.java +++ b/Mage.Sets/src/mage/cards/l/LavabornMuse.java @@ -30,7 +30,7 @@ public final class LavabornMuse extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Lavaborn Muse deals 3 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( TargetController.OPPONENT, - new DamageTargetEffect(3, true, "that player"), + new DamageTargetEffect(3).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/l/LazotepConvert.java b/Mage.Sets/src/mage/cards/l/LazotepConvert.java deleted file mode 100644 index 6c6bf532331..00000000000 --- a/Mage.Sets/src/mage/cards/l/LazotepConvert.java +++ /dev/null @@ -1,110 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.MageObject; -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CopyEffect; -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.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInGraveyard; -import mage.util.functions.CopyApplier; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LazotepConvert extends CardImpl { - - public LazotepConvert(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ZOMBIE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // You may have Lazotep Convert enter the battlefield as a copy of any creature card in a graveyard, except it's a 4/4 black Zombie in addition to its other types. - this.addAbility(new EntersBattlefieldAbility(new LazotepConvertCopyEffect(), true)); - } - - private LazotepConvert(final LazotepConvert card) { - super(card); - } - - @Override - public LazotepConvert copy() { - return new LazotepConvert(this); - } -} - -class LazotepConvertCopyEffect extends OneShotEffect { - - private static final CopyApplier applier = new CopyApplier() { - - @Override - public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { - blueprint.removePTCDA(); - blueprint.getPower().setModifiedBaseValue(4); - blueprint.getToughness().setModifiedBaseValue(4); - blueprint.addSubType(SubType.ZOMBIE); - blueprint.getColor().addColor(ObjectColor.BLACK); - return true; - } - }; - - private static final FilterCard filter = new FilterCreatureCard("creature card in a graveyard"); - - public LazotepConvertCopyEffect() { - super(Outcome.Copy); - this.staticText = "as a copy of any creature card in a graveyard, " + - "except it's a 4/4 black Zombie in addition to its other types"; - } - - private LazotepConvertCopyEffect(final LazotepConvertCopyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Target target = new TargetCardInGraveyard(0, 1, filter); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - Card copyFromCard = game.getCard(target.getFirstTarget()); - if (copyFromCard == null) { - return true; - } - Card modifiedCopy = copyFromCard.copy(); - //Appliers must be applied before CopyEffect, its applier setting is just for copies of copies - // TODO: research applier usage, why it here - applier.apply(game, modifiedCopy, source, source.getSourceId()); - game.addEffect(new CopyEffect( - Duration.Custom, modifiedCopy, source.getSourceId() - ).setApplier(applier), source); - return true; - } - - @Override - public LazotepConvertCopyEffect copy() { - return new LazotepConvertCopyEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LeavesFromTheVine.java b/Mage.Sets/src/mage/cards/l/LeavesFromTheVine.java new file mode 100644 index 00000000000..1046163cc73 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LeavesFromTheVine.java @@ -0,0 +1,86 @@ +package mage.cards.l; + +import mage.abilities.common.SagaAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.MillCardsControllerEffect; +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.SagaChapter; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LeavesFromTheVine extends CardImpl { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.LESSON.getPredicate() + )); + } + + private static final Condition condition = new CardsInControllerGraveyardCondition(1, filter); + private static final Hint hint = new ConditionHint( + condition, "There's a creature or Lesson card in your graveyard" + ); + + public LeavesFromTheVine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Mill three cards, then create a Food token. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, + new MillCardsControllerEffect(3), + new CreateTokenEffect(new FoodToken()).concatBy(", then") + ); + + // II -- Put a +1/+1 counter on each of up to two target creatures you control. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + new TargetControlledCreaturePermanent(0, 2) + ); + + // III -- Draw a card if there's a creature or Lesson card in your graveyard. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "draw a card if there's a creature or Lesson card in your graveyard" + ) + ); + this.addAbility(sagaAbility); + } + + private LeavesFromTheVine(final LeavesFromTheVine card) { + super(card); + } + + @Override + public LeavesFromTheVine copy() { + return new LeavesFromTheVine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeechingLurker.java b/Mage.Sets/src/mage/cards/l/LeechingLurker.java deleted file mode 100644 index 1fc7474793a..00000000000 --- a/Mage.Sets/src/mage/cards/l/LeechingLurker.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.NightboundAbility; -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 LeechingLurker extends CardImpl { - - public LeechingLurker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.LEECH); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private LeechingLurker(final LeechingLurker card) { - super(card); - } - - @Override - public LeechingLurker copy() { - return new LeechingLurker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LegionsLanding.java b/Mage.Sets/src/mage/cards/l/LegionsLanding.java index 7051affd2a3..3df75b5c68e 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsLanding.java +++ b/Mage.Sets/src/mage/cards/l/LegionsLanding.java @@ -1,14 +1,18 @@ - package mage.cards.l; +import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; import mage.game.permanent.token.IxalanVampireToken; @@ -17,21 +21,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LegionsLanding extends CardImpl { +public final class LegionsLanding extends TransformingDoubleFacedCard { public LegionsLanding(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); - - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.a.AdantoTheFirstFort.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{W}", + "Adanto, the First Fort", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Legion's Landing // When Legion's Landing enters the battlefield, create a 1/1 white Vampire creature token with lifelink. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new IxalanVampireToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new IxalanVampireToken()))); // When you attack with three or more creatures, transform Legion's Landing. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksWithCreaturesTriggeredAbility(new TransformSourceEffect(), 3).setTriggerPhrase("When you attack with three or more creatures, ")); + this.getLeftHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new TransformSourceEffect(), 3) + .setTriggerPhrase("When you attack with three or more creatures, ")); + + // Adanto, the First Fort + // {T}: Add {W}. + this.getRightHalfCard().addAbility(new WhiteManaAbility()); + + // {2}{W}, {T}: Create a 1/1 white Vampire creature token with lifelink. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new IxalanVampireToken()), new ManaCostsImpl<>("{2}{W}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); } private LegionsLanding(final LegionsLanding card) { diff --git a/Mage.Sets/src/mage/cards/l/LeonardoTheBalance.java b/Mage.Sets/src/mage/cards/l/LeonardoTheBalance.java new file mode 100644 index 00000000000..816a8f0226b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LeonardoTheBalance.java @@ -0,0 +1,73 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LeonardoTheBalance extends CardImpl { + + public LeonardoTheBalance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever a token you control enters, you may put a +1/+1 counter on each creature you control. Do this only once each turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ), StaticFilters.FILTER_PERMANENT_TOKEN + ).setDoOnlyOnceEachTurn(true)); + + // {W}{U}{B}{R}{G}: Creatures you control gain menace, trample, and lifelink until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityAllEffect( + new MenaceAbility(false), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("creatures you control gain menace"), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}") + ); + ability.addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText(", trample")); + ability.addEffect(new GainAbilityAllEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText(", and lifelink until end of turn")); + this.addAbility(ability); + + // Partner--Character select + this.addAbility(PartnerVariantType.CHARACTER_SELECT.makeAbility()); + } + + private LeonardoTheBalance(final LeonardoTheBalance card) { + super(card); + } + + @Override + public LeonardoTheBalance copy() { + return new LeonardoTheBalance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeonardoWorldlyWarrior.java b/Mage.Sets/src/mage/cards/l/LeonardoWorldlyWarrior.java new file mode 100644 index 00000000000..f93f88980ac --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LeonardoWorldlyWarrior.java @@ -0,0 +1,50 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.keyword.DoubleStrikeAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LeonardoWorldlyWarrior extends CardImpl { + + public LeonardoWorldlyWarrior(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // This spell costs {1} less to cast for each creature you control. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionForEachSourceEffect(1, CreaturesYouControlCount.SINGULAR) + ).addHint(CreaturesYouControlHint.instance)); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + } + + private LeonardoWorldlyWarrior(final LeonardoWorldlyWarrior card) { + super(card); + } + + @Override + public LeonardoWorldlyWarrior copy() { + return new LeonardoWorldlyWarrior(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeylineOfTheGuildpact.java b/Mage.Sets/src/mage/cards/l/LeylineOfTheGuildpact.java index a3de4e672b2..d3dcca61a2c 100644 --- a/Mage.Sets/src/mage/cards/l/LeylineOfTheGuildpact.java +++ b/Mage.Sets/src/mage/cards/l/LeylineOfTheGuildpact.java @@ -30,7 +30,7 @@ public final class LeylineOfTheGuildpact extends CardImpl { this.addAbility(new SimpleStaticAbility(new LeylineOfTheGuildpactEffect())); // Lands you control are every basic land type in addition to their other types. - this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect())); + this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect(Duration.WhileOnBattlefield))); } private LeylineOfTheGuildpact(final LeylineOfTheGuildpact card) { diff --git a/Mage.Sets/src/mage/cards/l/LeylineSurge.java b/Mage.Sets/src/mage/cards/l/LeylineSurge.java deleted file mode 100644 index 42a10f256e7..00000000000 --- a/Mage.Sets/src/mage/cards/l/LeylineSurge.java +++ /dev/null @@ -1,37 +0,0 @@ -package mage.cards.l; - -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LeylineSurge extends CardImpl { - - public LeylineSurge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setGreen(true); - this.nightCard = true; - - // At the beginning of your upkeep, you may put a permanent card from your hand onto the battlefield. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_A_PERMANENT) - )); - } - - private LeylineSurge(final LeylineSurge card) { - super(card); - } - - @Override - public LeylineSurge copy() { - return new LeylineSurge(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LifeOfToshiroUmezawa.java b/Mage.Sets/src/mage/cards/l/LifeOfToshiroUmezawa.java index 265927d6274..758cccf71b1 100644 --- a/Mage.Sets/src/mage/cards/l/LifeOfToshiroUmezawa.java +++ b/Mage.Sets/src/mage/cards/l/LifeOfToshiroUmezawa.java @@ -1,13 +1,17 @@ package mage.cards.l; +import mage.Mana; +import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SagaAbility; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.ConditionalColoredManaAbility; +import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; @@ -18,23 +22,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LifeOfToshiroUmezawa extends CardImpl { +public final class LifeOfToshiroUmezawa extends TransformingDoubleFacedCard { public LifeOfToshiroUmezawa(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.m.MemoryOfToshiro.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{B}", + "Memory of Toshiro", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SAMURAI}, "B" + ); + // Life of Toshiro Umezawa // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Choose one — // • Target creature gets +2/+2 until end of turn. // • Target creature gets -1/-1 until end of turn. // • You gain 2 life. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, false, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, false, ability -> { ability.addEffect(new BoostTargetEffect(2, 2)); ability.addTarget(new TargetCreaturePermanent()); @@ -45,10 +51,16 @@ public final class LifeOfToshiroUmezawa extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Memory of Toshiro + this.getRightHalfCard().setPT(2, 3); + + // {T}, Pay 1 life: Add {B}. Spend this mana only to cast an instant or sorcery spell. + Ability ability = new ConditionalColoredManaAbility(Mana.BlackMana(1), new InstantOrSorcerySpellManaBuilder()); + ability.addCost(new PayLifeCost(1)); + this.getRightHalfCard().addAbility(ability); } private LifeOfToshiroUmezawa(final LifeOfToshiroUmezawa card) { diff --git a/Mage.Sets/src/mage/cards/l/LightningSurge.java b/Mage.Sets/src/mage/cards/l/LightningSurge.java index 517f07f2347..4affdc01001 100644 --- a/Mage.Sets/src/mage/cards/l/LightningSurge.java +++ b/Mage.Sets/src/mage/cards/l/LightningSurge.java @@ -25,7 +25,7 @@ public final class LightningSurge extends CardImpl { // Lightning Surge deals 4 damage to any target. // Threshold - If seven or more cards are in your graveyard, instead Lightning Surge deals 6 damage to that creature or player and the damage can't be prevented. Effect effect = new ConditionalOneShotEffect( - new DamageTargetEffect(6, false), new DamageTargetEffect(4), + new DamageTargetEffect(6).withCantBePrevented(), new DamageTargetEffect(4), ThresholdCondition.instance, "{this} deals 4 damage to any target.
" + AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, " + "instead {this} deals 6 damage to that permanent or player and the damage can't be prevented" diff --git a/Mage.Sets/src/mage/cards/l/LightshieldArray.java b/Mage.Sets/src/mage/cards/l/LightshieldArray.java deleted file mode 100644 index 45076095e12..00000000000 --- a/Mage.Sets/src/mage/cards/l/LightshieldArray.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.l; - -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.HexproofAbility; -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.counters.CounterType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.watchers.common.AttackedThisTurnWatcher; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LightshieldArray extends CardImpl { - - public LightshieldArray(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.nightCard = true; - - // At the beginning of your end step, put a +1/+1 counter on each creature that attacked this turn. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - new LightshieldArrayEffect() - )); - - // Sacrifice Lightshield Array: Creatures you control gain hexproof and indestructible until end of turn. - Ability ability = new SimpleActivatedAbility(new GainAbilityControlledEffect( - HexproofAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("creatures you control gain hexproof"), new SacrificeSourceCost()); - ability.addEffect(new GainAbilityControlledEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("and indestructible until end of turn")); - this.addAbility(ability); - } - - private LightshieldArray(final LightshieldArray card) { - super(card); - } - - @Override - public LightshieldArray copy() { - return new LightshieldArray(this); - } -} - -class LightshieldArrayEffect extends OneShotEffect { - - LightshieldArrayEffect() { - super(Outcome.Benefit); - staticText = "put a +1/+1 counter on each creature that attacked this turn"; - } - - private LightshieldArrayEffect(final LightshieldArrayEffect effect) { - super(effect); - } - - @Override - public LightshieldArrayEffect copy() { - return new LightshieldArrayEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (MageObjectReference mor : game - .getState() - .getWatcher(AttackedThisTurnWatcher.class) - .getAttackedThisTurnCreatures()) { - Permanent permanent = mor.getPermanent(game); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(), source, game); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java b/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java deleted file mode 100644 index a2fa4b8c3b0..00000000000 --- a/Mage.Sets/src/mage/cards/l/LikenessOfTheSeeker.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; -import mage.abilities.effects.common.UntapLandsEffect; -import mage.constants.SubType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -/** - * - * @author weirddan455 - */ -public final class LikenessOfTheSeeker extends CardImpl { - - public LikenessOfTheSeeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.MONK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false)); - } - - private LikenessOfTheSeeker(final LikenessOfTheSeeker card) { - super(card); - } - - @Override - public LikenessOfTheSeeker copy() { - return new LikenessOfTheSeeker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java deleted file mode 100644 index a4250a436d0..00000000000 --- a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.l; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -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.SuperType; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicates; -import mage.game.command.emblems.LilianaDefiantNecromancerEmblem; -import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetadjustment.XManaValueTargetAdjuster; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class LilianaDefiantNecromancer extends CardImpl { - - private static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature card with mana value X from your graveyard"); - - static { - filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); - } - - public LilianaDefiantNecromancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.LILIANA); - this.color.setBlack(true); - - this.nightCard = true; - - this.setStartingLoyalty(3); - - // +2: Each player discards a card. - this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); - - // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. - Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); - ability.addTarget(new TargetCardInYourGraveyard(filter)); - ability.setTargetAdjuster(new XManaValueTargetAdjuster()); - this.addAbility(ability); - - //-8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new LilianaDefiantNecromancerEmblem()), -8)); - } - - private LilianaDefiantNecromancer(final LilianaDefiantNecromancer card) { - super(card); - } - - @Override - public LilianaDefiantNecromancer copy() { - return new LilianaDefiantNecromancer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java b/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java index 2f3557624a4..560727083e3 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java @@ -1,52 +1,76 @@ package mage.cards.l; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; 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.permanent.TokenPredicate; +import mage.game.command.emblems.LilianaDefiantNecromancerEmblem; import mage.game.permanent.token.ZombieToken; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.XManaValueTargetAdjuster; import java.util.UUID; /** * @author LevelX2 */ -public final class LilianaHereticalHealer extends CardImpl { +public final class LilianaHereticalHealer extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another nontoken creature you control"); + private static final FilterCreatureCard graveyardFilter = new FilterCreatureCard("nonlegendary creature card with mana value X from your graveyard"); static { filter.add(AnotherPredicate.instance); filter.add(TokenPredicate.FALSE); + graveyardFilter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); } public LilianaHereticalHealer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{1}{B}{B}", + "Liliana, Defiant Necromancer", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.LILIANA}, "B" + ); - this.secondSideCardClazz = mage.cards.l.LilianaDefiantNecromancer.class; - this.addAbility(new TransformAbility()); + // Liliana, Heretical Healer + this.getLeftHalfCard().setPT(2, 3); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, create a 2/2 black Zombie creature token. - this.addAbility(new DiesCreatureTriggeredAbility(new ExileAndReturnSourceEffect( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(new ExileAndReturnSourceEffect( PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE, false, new CreateTokenEffect(new ZombieToken()) ), false, filter)); + + // Liliana, Defiant Necromancer + this.getRightHalfCard().setStartingLoyalty(3); + + // +2: Each player discards a card. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); + + // -X: Return target nonlegendary creature with mana value X from your graveyard to the battlefield. + Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(graveyardFilter)); + ability.setTargetAdjuster(new XManaValueTargetAdjuster()); + this.getRightHalfCard().addAbility(ability); + + // -8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step." + this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new LilianaDefiantNecromancerEmblem()), -8)); } private LilianaHereticalHealer(final LilianaHereticalHealer card) { diff --git a/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java b/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java deleted file mode 100644 index 861156384e3..00000000000 --- a/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java +++ /dev/null @@ -1,103 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LivingBreakthrough extends CardImpl { - - public LivingBreakthrough(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.MOONFOLK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever you cast a spell, your opponents can't cast spells with the same mana value as that spell until your next turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new LivingBreakthroughEffect(), false)); - } - - private LivingBreakthrough(final LivingBreakthrough card) { - super(card); - } - - @Override - public LivingBreakthrough copy() { - return new LivingBreakthrough(this); - } -} - -class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl { - - private int manaValue = -1; - - LivingBreakthroughEffect() { - super(Duration.UntilYourNextTurn, Outcome.Benefit); - staticText = "your opponents can't cast spells with the same mana value as that spell until your next turn"; - } - - private LivingBreakthroughEffect(final LivingBreakthroughEffect effect) { - super(effect); - this.manaValue = effect.manaValue; - } - - @Override - public LivingBreakthroughEffect copy() { - return new LivingBreakthroughEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - Spell spell = (Spell) getValue("spellCast"); - if (spell != null) { - this.manaValue = spell.getManaValue(); - } - } - - @Override - public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source); - if (mageObject != null) { - return "You can't cast spells with mana value " + manaValue - + " this turn (" + mageObject.getIdName() + ")."; - } - return null; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL_LATE; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - return false; - } - Spell spell = game.getStack().getSpell(event.getTargetId()); - return spell != null && spell.getManaValue() == this.manaValue; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LizardConnorssCurse.java b/Mage.Sets/src/mage/cards/l/LizardConnorssCurse.java index c67ae20fb01..f6a9cf7a521 100644 --- a/Mage.Sets/src/mage/cards/l/LizardConnorssCurse.java +++ b/Mage.Sets/src/mage/cards/l/LizardConnorssCurse.java @@ -46,7 +46,7 @@ public final class LizardConnorssCurse extends CardImpl { CreatureToken token = new CreatureToken(4, 4, "green Lizard creature with base power and toughness 4/4", SubType.LIZARD) .withColor("G"); Ability ability = new EntersBattlefieldTriggeredAbility( - new BecomesCreatureTargetEffect(token, true, false, Duration.WhileOnBattlefield) + new BecomesCreatureTargetEffect(token, true, false, Duration.Custom) ); ability.addTarget(new TargetPermanent(0, 1, filter)); ability.withFlavorWord("Lizard Formula"); diff --git a/Mage.Sets/src/mage/cards/l/LoAndLiRoyalAdvisors.java b/Mage.Sets/src/mage/cards/l/LoAndLiRoyalAdvisors.java new file mode 100644 index 00000000000..e81990cf725 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoAndLiRoyalAdvisors.java @@ -0,0 +1,86 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +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.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LoAndLiRoyalAdvisors extends CardImpl { + + public LoAndLiRoyalAdvisors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever an opponent discards a card or mills one or more cards, put a +1/+1 counter on each Advisor you control. + this.addAbility(new LoAndLiRoyalAdvisorsTriggeredAbility()); + + // {2}{U/B}: Target player mills four cards. + Ability ability = new SimpleActivatedAbility(new MillCardsTargetEffect(4), new ManaCostsImpl<>("{2}{U/B}")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private LoAndLiRoyalAdvisors(final LoAndLiRoyalAdvisors card) { + super(card); + } + + @Override + public LoAndLiRoyalAdvisors copy() { + return new LoAndLiRoyalAdvisors(this); + } +} + +class LoAndLiRoyalAdvisorsTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ADVISOR); + + LoAndLiRoyalAdvisorsTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter)); + setTriggerPhrase("Whenever an opponent discards a card or mills one or more cards, "); + } + + private LoAndLiRoyalAdvisorsTriggeredAbility(final LoAndLiRoyalAdvisorsTriggeredAbility ability) { + super(ability); + } + + @Override + public LoAndLiRoyalAdvisorsTriggeredAbility copy() { + return new LoAndLiRoyalAdvisorsTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DISCARDED_CARD + || event.getType() == GameEvent.EventType.MILLED_CARDS_BATCH_FOR_ONE_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getOpponents(getControllerId()).contains(event.getPlayerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LoAndLiTwinTutors.java b/Mage.Sets/src/mage/cards/l/LoAndLiTwinTutors.java new file mode 100644 index 00000000000..0a7fd5d7a44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoAndLiTwinTutors.java @@ -0,0 +1,75 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +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.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LoAndLiTwinTutors extends CardImpl { + + private static final FilterCard filter = new FilterCard("a Lesson or Noble card"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent(SubType.NOBLE, ""); + private static final FilterNonlandCard filter3 = new FilterNonlandCard("Lesson spells you control"); + + static { + filter.add(Predicates.or( + SubType.LESSON.getPredicate(), + SubType.NOBLE.getPredicate() + )); + filter3.add(SubType.LESSON.getPredicate()); + } + + public LoAndLiTwinTutors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Lo and Li enter, search your library for a Lesson or Noble card, reveal it, put it into your hand, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) + ).setTriggerPhrase("When {this} enter, ")); + + // Noble creatures you control and Lesson spells you control have lifelink. + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, filter2 + ).setText("Noble creatures you control")); + ability.addEffect(new GainAbilityControlledSpellsEffect( + LifelinkAbility.getInstance(), filter3 + ).concatBy("and")); + this.addAbility(ability); + } + + private LoAndLiTwinTutors(final LoAndLiTwinTutors card) { + super(card); + } + + @Override + public LoAndLiTwinTutors copy() { + return new LoAndLiTwinTutors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LocusOfEnlightenment.java b/Mage.Sets/src/mage/cards/l/LocusOfEnlightenment.java deleted file mode 100644 index 190c43c56fc..00000000000 --- a/Mage.Sets/src/mage/cards/l/LocusOfEnlightenment.java +++ /dev/null @@ -1,98 +0,0 @@ -package mage.cards.l; - -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.common.ActivateAbilityTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.CopyStackObjectEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterStackObject; -import mage.filter.common.FilterActivatedOrTriggeredAbility; -import mage.filter.predicate.other.NotManaAbilityPredicate; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LocusOfEnlightenment extends CardImpl { - private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability that isn't a mana ability"); - - static { - filter.add(NotManaAbilityPredicate.instance); - } - public LocusOfEnlightenment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - this.color.setBlue(true); - - // Locus of Enlightenment has each activated ability of the exiled cards used to craft it. You may activate each of those abilities only once each turn. - this.addAbility(new SimpleStaticAbility(new LocusOfEnlightenmentEffect())); - - // Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy. - this.addAbility(new ActivateAbilityTriggeredAbility(new CopyStackObjectEffect("it"), filter, SetTargetPointer.SPELL)); - } - - private LocusOfEnlightenment(final LocusOfEnlightenment card) { - super(card); - } - - @Override - public LocusOfEnlightenment copy() { - return new LocusOfEnlightenment(this); - } -} - -class LocusOfEnlightenmentEffect extends ContinuousEffectImpl { - - LocusOfEnlightenmentEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.Benefit); - staticText = "{this} has each activated ability of the exiled cards " + - "used to craft it. You may activate each of those abilities only once each turn"; - } - - private LocusOfEnlightenmentEffect(final LocusOfEnlightenmentEffect effect) { - super(effect); - } - - @Override - public LocusOfEnlightenmentEffect copy() { - return new LocusOfEnlightenmentEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return false; - } - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, permanent.getId(), permanent.getZoneChangeCounter(game) - 2 - )); - if (exileZone == null) { - return false; - } - for (Card card : exileZone.getCards(game)) { - for (Ability ability : card.getAbilities(game)) { - if (ability.isActivatedAbility()) { - ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); - copyAbility.setMaxActivationsPerTurn(1); - permanent.addAbility(copyAbility, source.getSourceId(), game, true); - } - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LodestoneNeedle.java b/Mage.Sets/src/mage/cards/l/LodestoneNeedle.java index a68ba5a2eb1..3a04293fad3 100644 --- a/Mage.Sets/src/mage/cards/l/LodestoneNeedle.java +++ b/Mage.Sets/src/mage/cards/l/LodestoneNeedle.java @@ -1,41 +1,58 @@ package mage.cards.l; import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.keyword.ExploreTargetEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.keyword.FlashAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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; /** * @author Susucr */ -public final class LodestoneNeedle extends CardImpl { +public final class LodestoneNeedle extends TransformingDoubleFacedCard { public LodestoneNeedle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); - this.secondSideCardClazz = mage.cards.g.GuidestoneCompass.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{U}", + "Guidestone Compass", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U" + ); + // Lodestone Needle // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // When Lodestone Needle enters the battlefield, tap up to one target artifact or creature and put two stun counters on it. Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance(2)) .setText("and put two stun counters on it")); ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {2}{U} - this.addAbility(new CraftAbility("{2}{U}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{2}{U}")); + + // Guidestone Compass + // {1}, {T}: Target creature you control explores. Activate only as a sorcery. + Ability compassAbility = new ActivateAsSorceryActivatedAbility(new ExploreTargetEffect(), new GenericManaCost(1)); + compassAbility.addTarget(new TargetControlledCreaturePermanent()); + compassAbility.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(compassAbility); } private LodestoneNeedle(final LodestoneNeedle card) { diff --git a/Mage.Sets/src/mage/cards/l/LoneRider.java b/Mage.Sets/src/mage/cards/l/LoneRider.java index c6450c5473a..848c4ff6282 100644 --- a/Mage.Sets/src/mage/cards/l/LoneRider.java +++ b/Mage.Sets/src/mage/cards/l/LoneRider.java @@ -1,16 +1,16 @@ package mage.cards.l; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; @@ -22,30 +22,46 @@ import java.util.UUID; /** * @author fireshoes */ -public final class LoneRider extends CardImpl { +public final class LoneRider extends TransformingDoubleFacedCard { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); public LoneRider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "{1}{W}", + "It That Rides as One", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.HORROR}, "" + ); - this.secondSideCardClazz = mage.cards.i.ItThatRidesAsOne.class; + // Lone Rider + this.getLeftHalfCard().setPT(1, 1); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // At the beginning of the end step, if you gained 3 or more life this turn, transform Lone Rider. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( - TargetController.NEXT, new TransformSourceEffect(), false - ).withInterveningIf(condition).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); + Ability ability = new BeginningOfEndStepTriggeredAbility( + TargetController.NEXT, new TransformSourceEffect(), false) + .withInterveningIf(condition) + .addHint(ControllerGainedLifeCount.getHint() + ); + ability.addWatcher(new PlayerGainedLifeWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // It That Rides as One + this.getRightHalfCard().setPT(4, 4); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); } private LoneRider(final LoneRider card) { diff --git a/Mage.Sets/src/mage/cards/l/LoneWolfOfTheNatterknolls.java b/Mage.Sets/src/mage/cards/l/LoneWolfOfTheNatterknolls.java deleted file mode 100644 index 76c89b0d922..00000000000 --- a/Mage.Sets/src/mage/cards/l/LoneWolfOfTheNatterknolls.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.condition.common.MyTurnCondition; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -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 LevelX2 - */ -public final class LoneWolfOfTheNatterknolls extends CardImpl { - - public LoneWolfOfTheNatterknolls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setGreen(true); - - this.nightCard = true; - - // Whenever an opponent cast a spell during your turn, draw two cards. - this.addAbility(new SpellCastOpponentTriggeredAbility( - new DrawCardSourceControllerEffect(2), StaticFilters.FILTER_SPELL_A, false - ).withTriggerCondition(MyTurnCondition.instance)); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lone Wolf of the Natterknolls. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private LoneWolfOfTheNatterknolls(final LoneWolfOfTheNatterknolls card) { - super(card); - } - - @Override - public LoneWolfOfTheNatterknolls copy() { - return new LoneWolfOfTheNatterknolls(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java b/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java index 95abf6d63d5..0bb6414a7a7 100644 --- a/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java +++ b/Mage.Sets/src/mage/cards/l/LongListOfTheEnts.java @@ -53,8 +53,8 @@ public final class LongListOfTheEnts extends CardImpl { return new LongListOfTheEnts(this); } - static String getKey(Game game, Ability source, int offset) { - return "EntList_" + source.getSourceId() + "_" + (offset + CardUtil.getActualSourceObjectZoneChangeCounter(game, source)); + static String getKey(Game game, Ability source) { + return "EntList_" + source.getSourceId() + "_" + CardUtil.getActualSourceObjectZoneChangeCounter(game, source); } } @@ -67,7 +67,7 @@ enum LongListOfTheEntsHint implements Hint { if (ability.getSourcePermanentIfItStillExists(game) == null) { return null; } - Set subTypes = (Set) game.getState().getValue(LongListOfTheEnts.getKey(game, ability, 0)); + Set subTypes = (Set) game.getState().getValue(LongListOfTheEnts.getKey(game, ability)); if (subTypes == null || subTypes.isEmpty()) { return "No creature types have been noted yet."; } @@ -109,14 +109,11 @@ class LongListOfTheEntsEffect extends OneShotEffect { return false; } - Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source, 0)); - int offset; + Object existingEntList = game.getState().getValue(LongListOfTheEnts.getKey(game, source)); Set newEntList; if (existingEntList == null) { - offset = 1; // zcc is off-by-one due to still entering battlefield newEntList = new LinkedHashSet<>(); } else { - offset = 0; newEntList = new LinkedHashSet<>((Set) existingEntList); } Set chosenTypes = newEntList @@ -132,7 +129,7 @@ class LongListOfTheEntsEffect extends OneShotEffect { SubType subType = SubType.byDescription(choice.getChoiceKey()); game.informPlayers(player.getLogName() + " notes the creature type " + subType); newEntList.add(subType); - game.getState().setValue(LongListOfTheEnts.getKey(game, source, offset), newEntList); + game.getState().setValue(LongListOfTheEnts.getKey(game, source), newEntList); FilterSpell filter = new FilterCreatureSpell("a creature spell of that type"); filter.add(subType.getPredicate()); game.addDelayedTriggeredAbility(new AddCounterNextSpellDelayedTriggeredAbility(filter), source); diff --git a/Mage.Sets/src/mage/cards/l/LongshotRebelBowman.java b/Mage.Sets/src/mage/cards/l/LongshotRebelBowman.java new file mode 100644 index 00000000000..e5501216631 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LongshotRebelBowman.java @@ -0,0 +1,63 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LongshotRebelBowman extends CardImpl { + + private static final FilterCard filter = new FilterCard("noncreature spells"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + public LongshotRebelBowman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Noncreature spells you cast cost {1} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); + + // Whenever you cast a noncreature spell, Longshot deals 2 damage to each opponent. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DamagePlayersEffect(2, TargetController.OPPONENT), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + } + + private LongshotRebelBowman(final LongshotRebelBowman card) { + super(card); + } + + @Override + public LongshotRebelBowman copy() { + return new LongshotRebelBowman(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LordOfLineage.java b/Mage.Sets/src/mage/cards/l/LordOfLineage.java deleted file mode 100644 index 3480656c2d1..00000000000 --- a/Mage.Sets/src/mage/cards/l/LordOfLineage.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -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.BoostControlledEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.permanent.token.VampireToken; - -/** - * - * @author Loki - */ -public final class LordOfLineage extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VAMPIRE, "Vampire creatures"); - - public LordOfLineage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.VAMPIRE); - - this.color.setBlack(true); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card Bloodline Keeper - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Other Vampire creatures you control get +2/+2. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true))); - - // {T}: Create a 2/2 black Vampire creature token with flying. - this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new VampireToken()), new TapSourceCost())); - } - - private LordOfLineage(final LordOfLineage card) { - super(card); - } - - @Override - public LordOfLineage copy() { - return new LordOfLineage(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LordOfTheUlvenwald.java b/Mage.Sets/src/mage/cards/l/LordOfTheUlvenwald.java deleted file mode 100644 index 7fed8fc3c0f..00000000000 --- a/Mage.Sets/src/mage/cards/l/LordOfTheUlvenwald.java +++ /dev/null @@ -1,100 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.Mana; -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.BoostControlledEffect; -import mage.abilities.keyword.NightboundAbility; -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.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LordOfTheUlvenwald extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wolves and Werewolves"); - - static { - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public LordOfTheUlvenwald(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Other Wolves and Werewolves you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 1, 1, Duration.WhileOnBattlefield, filter, true - ))); - - // Whenever Lord of the Ulvenwald attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end. - this.addAbility(new AttacksTriggeredAbility(new LordOfTheUlvenwaldEffect())); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private LordOfTheUlvenwald(final LordOfTheUlvenwald card) { - super(card); - } - - @Override - public LordOfTheUlvenwald copy() { - return new LordOfTheUlvenwald(this); - } -} - -class LordOfTheUlvenwaldEffect extends OneShotEffect { - - LordOfTheUlvenwaldEffect() { - super(Outcome.Benefit); - staticText = "add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end"; - } - - private LordOfTheUlvenwaldEffect(final LordOfTheUlvenwaldEffect effect) { - super(effect); - } - - @Override - public LordOfTheUlvenwaldEffect copy() { - return new LordOfTheUlvenwaldEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Mana mana = player.chooseUse( - Outcome.Neutral, "Choose red or green", null, - "Red", "Green", source, game - ) ? Mana.RedMana(1) : Mana.GreenMana(1); - player.getManaPool().addMana(mana, game, source, true); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LostDays.java b/Mage.Sets/src/mage/cards/l/LostDays.java new file mode 100644 index 00000000000..92d8967e83d --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LostDays.java @@ -0,0 +1,39 @@ +package mage.cards.l; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +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.ClueArtifactToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LostDays extends CardImpl { + + public LostDays(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}"); + + this.subtype.add(SubType.LESSON); + + // The owner of target creature or enchantment puts it into their library second from the top or on the bottom. You create a Clue token. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("You")); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_OR_ENCHANTMENT)); + } + + private LostDays(final LostDays card) { + super(card); + } + + @Override + public LostDays copy() { + return new LostDays(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LostInMemories.java b/Mage.Sets/src/mage/cards/l/LostInMemories.java new file mode 100644 index 00000000000..cf363c9638a --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LostInMemories.java @@ -0,0 +1,95 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +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.FlashbackAbility; +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.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LostInMemories extends CardImpl { + + public LostInMemories(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature gets +1/+1 and has "Whenever this creature deals combat damage to a player, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost." + TriggeredAbility triggeredAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new LostInMemoriesEffect()); + triggeredAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY)); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect(triggeredAbility, AttachmentType.AURA) + .setText("and has \"Whenever this creature deals combat damage to a player, " + + "target instant or sorcery card in your graveyard gains flashback until end of turn. " + + "The flashback cost is equal to its mana cost.\"")); + this.addAbility(ability); + } + + private LostInMemories(final LostInMemories card) { + super(card); + } + + @Override + public LostInMemories copy() { + return new LostInMemories(this); + } +} + +class LostInMemoriesEffect extends ContinuousEffectImpl { + + LostInMemoriesEffect() { + super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.staticText = "target instant or sorcery card in your graveyard gains flashback until end of turn. " + + "The flashback cost is equal to its mana cost"; + } + + private LostInMemoriesEffect(final LostInMemoriesEffect effect) { + super(effect); + } + + @Override + public LostInMemoriesEffect copy() { + return new LostInMemoriesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + return false; + } + FlashbackAbility ability = new FlashbackAbility(card, card.getManaCost()); + ability.setSourceId(card.getId()); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LostVale.java b/Mage.Sets/src/mage/cards/l/LostVale.java deleted file mode 100644 index 2936d1430ff..00000000000 --- a/Mage.Sets/src/mage/cards/l/LostVale.java +++ /dev/null @@ -1,34 +0,0 @@ -package mage.cards.l; - -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class LostVale extends CardImpl { - - public LostVale(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // T: Add three mana of any one color. - this.addAbility(new SimpleManaAbility(new AddManaOfAnyColorEffect(3), new TapSourceCost())); - } - - private LostVale(final LostVale card) { - super(card); - } - - @Override - public LostVale copy() { - return new LostVale(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LoyalCathar.java b/Mage.Sets/src/mage/cards/l/LoyalCathar.java index b6c4857f69d..41bb3659fc3 100644 --- a/Mage.Sets/src/mage/cards/l/LoyalCathar.java +++ b/Mage.Sets/src/mage/cards/l/LoyalCathar.java @@ -1,10 +1,7 @@ - package mage.cards.l; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.CantBlockAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; @@ -12,8 +9,8 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -22,26 +19,31 @@ import mage.game.Game; import mage.players.Player; import mage.target.targetpointer.FixedTarget; -/** - * @author BetaSteward - */ -public final class LoyalCathar extends CardImpl { +import java.util.UUID; + +public final class LoyalCathar extends TransformingDoubleFacedCard { public LoyalCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{W}{W}", + "Unhallowed Cathar", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE, SubType.SOLDIER}, "B" + ); - this.secondSideCardClazz = mage.cards.u.UnhallowedCathar.class; + // Loyal Cathar + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - this.addAbility(VigilanceAbility.getInstance()); + // Vigilance + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // When Loyal Cathar dies, return it to the battlefield transformed under your control at the beginning of the next end step. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new LoyalCatharEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new LoyalCatharEffect())); + + // Unhallowed Cathar + this.getRightHalfCard().setPT(2, 1); + + // Unhallowed Cathar can't block. + this.getRightHalfCard().addAbility(new CantBlockAbility()); } private LoyalCathar(final LoyalCathar card) { diff --git a/Mage.Sets/src/mage/cards/l/LoyalPegasus.java b/Mage.Sets/src/mage/cards/l/LoyalPegasus.java index b817a1d9443..4ec250d15e5 100644 --- a/Mage.Sets/src/mage/cards/l/LoyalPegasus.java +++ b/Mage.Sets/src/mage/cards/l/LoyalPegasus.java @@ -1,24 +1,23 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; 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 LevelX2 */ public final class LoyalPegasus extends CardImpl { public LoyalPegasus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.PEGASUS); this.power = new MageInt(2); @@ -27,8 +26,7 @@ public final class LoyalPegasus extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Loyal Pegasus can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private LoyalPegasus(final LoyalPegasus card) { diff --git a/Mage.Sets/src/mage/cards/l/LudevicNecrogenius.java b/Mage.Sets/src/mage/cards/l/LudevicNecrogenius.java index dae5e612be0..0dd0cd31069 100644 --- a/Mage.Sets/src/mage/cards/l/LudevicNecrogenius.java +++ b/Mage.Sets/src/mage/cards/l/LudevicNecrogenius.java @@ -1,53 +1,66 @@ package mage.cards.l; -import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileXFromYourGraveCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.*; +import mage.constants.*; import mage.filter.StaticFilters; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; import mage.util.CardUtil; +import mage.util.functions.CopyApplier; import java.util.UUID; /** * @author TheElk801 */ -public final class LudevicNecrogenius extends CardImpl { +public final class LudevicNecrogenius extends TransformingDoubleFacedCard { public LudevicNecrogenius(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{U}{B}", + "Olag, Ludevic's Hubris", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ZOMBIE}, "UB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.o.OlagLudevicsHubris.class; + // Ludevic, Necrogenius + this.getLeftHalfCard().setPT(2, 3); // Whenever Ludevic, Necrogenius enters the battlefield or attacks, mill a card. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new MillCardsControllerEffect(1))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new MillCardsControllerEffect(1))); // {X}{U}{U}{B}{B}, Exile X creature cards from your graveyard: Transform Ludevic, Necrogenius. X can't be zero. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{X}{U}{U}{B}{B}") ); ability.addEffect(new InfoEffect("X can't be 0")); ability.addCost(new ExileXFromYourGraveCost(StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD)); CardUtil.castStream(ability.getCosts().stream(), VariableManaCost.class).forEach(cost -> cost.setMinX(1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Olag, Ludevic's Hubris + this.getRightHalfCard().setPT(4, 4); + + // As this creature transforms in Olag, Ludevic's Hubris, it becomes a copy of a creature card exiled with it, except its name is Olag, Ludevic's Hubris, it's 4/4, and it's a legendary blue and black Zombie in addition to its other colors and types. Put a number of +1/+1 counters on Olag equal to the number of creature cards exiled with it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new OlagLudevicsHubrisEffect())); } private LudevicNecrogenius(final LudevicNecrogenius card) { @@ -59,3 +72,92 @@ public final class LudevicNecrogenius extends CardImpl { return new LudevicNecrogenius(this); } } + + +class OlagLudevicsHubrisEffect extends ReplacementEffectImpl { + + OlagLudevicsHubrisEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "as this creature transforms into {this}, it becomes a copy of a creature card exiled with it, " + + "except its name is Olag, Ludevic's Hubris, it's 4/4, and it's a legendary blue and black " + + "Zombie in addition to its other colors and types. Put a number of +1/+1 counters on {this} " + + "equal to the number of creature cards exiled with it"; + } + + private OlagLudevicsHubrisEffect(final OlagLudevicsHubrisEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone == null) { + return false; + } + + Cards cards = new CardsImpl(exileZone); + cards.removeIf(uuid -> !game.getCard(uuid).isCreature(game)); + if (cards.isEmpty()) { + return false; + } + + Card copyFromCard = getCard(cards, source, game); + if (copyFromCard == null) { + return false; + } + Permanent newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); + newBluePrint.assignNewId(); + CopyApplier applier = new OlagLudevicsHubrisCopyApplier(); + applier.apply(game, newBluePrint, source, source.getSourceId()); + CopyEffect copyEffect = new CopyEffect(Duration.Custom, newBluePrint, source.getSourceId()); + copyEffect.setApplier(applier); + Ability newAbility = source.copy(); + copyEffect.init(newAbility, game); + game.addEffect(copyEffect, newAbility); + return false; + } + + private Card getCard(Cards cards, Ability source, Game game) { + if (cards.size() == 1) { + return cards.getRandom(game); + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return cards.getRandom(game); + } + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); + player.choose(outcome, target, source, game); + return cards.get(target.getFirstTarget(), game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TRANSFORMING; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getSourceId().equals(event.getTargetId()) + && source.getSourcePermanentIfItStillExists(game) != null; + } + + @Override + public OlagLudevicsHubrisEffect copy() { + return new OlagLudevicsHubrisEffect(this); + } +} + +class OlagLudevicsHubrisCopyApplier extends CopyApplier { + + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { + blueprint.setName("Olag, Ludevic's Hubris"); + blueprint.addSuperType(SuperType.LEGENDARY); + blueprint.addSubType(SubType.ZOMBIE); + blueprint.getColor().setBlue(true); + blueprint.getColor().setBlack(true); + blueprint.getPower().setModifiedBaseValue(4); + blueprint.getToughness().setModifiedBaseValue(4); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LudevicsAbomination.java b/Mage.Sets/src/mage/cards/l/LudevicsAbomination.java deleted file mode 100644 index dcfe9517ef7..00000000000 --- a/Mage.Sets/src/mage/cards/l/LudevicsAbomination.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.l; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author North - */ -public final class LudevicsAbomination extends CardImpl { - - public LudevicsAbomination(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.LIZARD); - this.subtype.add(SubType.HORROR); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(13); - this.toughness = new MageInt(13); - - this.addAbility(TrampleAbility.getInstance()); - } - - private LudevicsAbomination(final LudevicsAbomination card) { - super(card); - } - - @Override - public LudevicsAbomination copy() { - return new LudevicsAbomination(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LudevicsTestSubject.java b/Mage.Sets/src/mage/cards/l/LudevicsTestSubject.java index 4dd297875f1..57512b0ec94 100644 --- a/Mage.Sets/src/mage/cards/l/LudevicsTestSubject.java +++ b/Mage.Sets/src/mage/cards/l/LudevicsTestSubject.java @@ -1,6 +1,5 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; @@ -11,9 +10,9 @@ import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; @@ -23,23 +22,24 @@ import java.util.UUID; /** * @author Loki */ -public final class LudevicsTestSubject extends CardImpl { +public final class LudevicsTestSubject extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.HATCHLING, 5); public LudevicsTestSubject(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.LIZARD, SubType.EGG); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.LIZARD, SubType.EGG}, "{1}{U}", + "Ludevic's Abomination", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.LIZARD, SubType.HORROR}, "U" + ); - this.power = new MageInt(0); - this.toughness = new MageInt(3); + // Ludevic's Test Subject + this.getLeftHalfCard().setPT(0, 3); - this.secondSideCardClazz = mage.cards.l.LudevicsAbomination.class; - - this.addAbility(DefenderAbility.getInstance()); + // Defender + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {1}{U}: Put a hatchling counter on Ludevic's Test Subject. Then if there are five or more hatchling counters on it, remove all of them and transform it. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility( new AddCountersSourceEffect(CounterType.HATCHLING.createInstance()), new ManaCostsImpl<>("{1}{U}") ); @@ -47,7 +47,13 @@ public final class LudevicsTestSubject extends CardImpl { new RemoveAllCountersSourceEffect(CounterType.HATCHLING), condition, "Then if there are five or more hatchling counters on it, remove all of them and transform it" ).addEffect(new TransformSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Ludevic's Abomination + this.getRightHalfCard().setPT(13, 13); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); } private LudevicsTestSubject(final LudevicsTestSubject card) { diff --git a/Mage.Sets/src/mage/cards/l/LuminousPhantom.java b/Mage.Sets/src/mage/cards/l/LuminousPhantom.java deleted file mode 100644 index 123b2665457..00000000000 --- a/Mage.Sets/src/mage/cards/l/LuminousPhantom.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.keyword.DisturbAbility; -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 LuminousPhantom extends CardImpl { - - public LuminousPhantom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever another creature you control leaves the battlefield, you gain 1 life. - this.addAbility(new LeavesBattlefieldAllTriggeredAbility(new GainLifeEffect(1), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); - - // If Luminous Phantom would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private LuminousPhantom(final LuminousPhantom card) { - super(card); - } - - @Override - public LuminousPhantom copy() { - return new LuminousPhantom(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java b/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java deleted file mode 100644 index 191be943d48..00000000000 --- a/Mage.Sets/src/mage/cards/l/LunarchInquisitors.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.l; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class LunarchInquisitors extends CardImpl { - - public LunarchInquisitors(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // When this creature transforms into Lunarch Inquisitors, you may exile another target creature until Lunarch Inquisitors leaves the battlefield. - Ability ability = new TransformIntoSourceTriggeredAbility(new ExileUntilSourceLeavesEffect(), true); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); - this.addAbility(ability); - } - - private LunarchInquisitors(final LunarchInquisitors card) { - super(card); - } - - @Override - public LunarchInquisitors copy() { - return new LunarchInquisitors(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LunarchVeteran.java b/Mage.Sets/src/mage/cards/l/LunarchVeteran.java index 22eb68fa555..d96df1d99ae 100644 --- a/Mage.Sets/src/mage/cards/l/LunarchVeteran.java +++ b/Mage.Sets/src/mage/cards/l/LunarchVeteran.java @@ -1,12 +1,12 @@ package mage.cards.l; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -16,24 +16,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LunarchVeteran extends CardImpl { +public final class LunarchVeteran extends TransformingDoubleFacedCard { public LunarchVeteran(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{W}", + "Luminous Phantom", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.CLERIC}, "W" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.l.LuminousPhantom.class; + // Lunarch Veteran + this.getLeftHalfCard().setPT(1, 1); // Whenever another creature you control enters, you gain 1 life. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldControlledTriggeredAbility( new GainLifeEffect(1), StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE )); // Disturb {1}{W} - this.addAbility(new DisturbAbility(this, "{1}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{W}")); + + // Luminous Phantom + this.getRightHalfCard().setPT(1, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever another creature you control leaves the battlefield, you gain 1 life. + this.getRightHalfCard().addAbility(new LeavesBattlefieldAllTriggeredAbility( + new GainLifeEffect(1), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL + )); + + // If Luminous Phantom would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private LunarchVeteran(final LunarchVeteran card) { diff --git a/Mage.Sets/src/mage/cards/l/Lunge.java b/Mage.Sets/src/mage/cards/l/Lunge.java index b3bb6efb96f..feb397b976c 100644 --- a/Mage.Sets/src/mage/cards/l/Lunge.java +++ b/Mage.Sets/src/mage/cards/l/Lunge.java @@ -1,15 +1,13 @@ - package mage.cards.l; -import java.util.UUID; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; -import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; /** * @@ -21,14 +19,10 @@ public final class Lunge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Lunge deals 2 damage to target creature and 2 damage to target player. - this.getSpellAbility().addEffect(new DamageTargetEffect(2).setUseOnlyTargetPointer(true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(2)); - Effect effect = new DamageTargetEffect(2).setUseOnlyTargetPointer(true); - effect.setTargetPointer(new SecondTargetPointer()); - effect.setText("and 2 damage to target player or planeswalker"); - this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); } private Lunge(final Lunge card) { diff --git a/Mage.Sets/src/mage/cards/m/MagebaneArmor.java b/Mage.Sets/src/mage/cards/m/MagebaneArmor.java index a34fa10a68d..fdd45252d5f 100644 --- a/Mage.Sets/src/mage/cards/m/MagebaneArmor.java +++ b/Mage.Sets/src/mage/cards/m/MagebaneArmor.java @@ -15,8 +15,6 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import java.util.UUID; @@ -86,21 +84,6 @@ class MagebaneArmorPreventionEffect extends PreventionEffectImpl { return new MagebaneArmorPreventionEffect(this); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int damage = event.getAmount(); - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - return true; - } - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game) && !((DamageEvent) event).isCombatDamage()) { diff --git a/Mage.Sets/src/mage/cards/m/MagickedCard.java b/Mage.Sets/src/mage/cards/m/MagickedCard.java deleted file mode 100644 index 08ee1d907fb..00000000000 --- a/Mage.Sets/src/mage/cards/m/MagickedCard.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MagickedCard extends CardImpl { - - public MagickedCard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setBlue(true); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - } - - private MagickedCard(final MagickedCard card) { - super(card); - } - - @Override - public MagickedCard copy() { - return new MagickedCard(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java b/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java index e07c277a4e8..2fa259f8e8f 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java @@ -1,17 +1,12 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.mana.RedManaAbility; +import mage.abilities.effects.common.continuous.NonbasicLandsAreMountainsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.CardType; +import mage.constants.SubType; import java.util.UUID; @@ -29,7 +24,7 @@ public final class MagusOfTheMoon extends CardImpl { this.toughness = new MageInt(2); // Nonbasic lands are Mountains. - this.addAbility(new SimpleStaticAbility(new MagusOfTheMoonEffect())); + this.addAbility(new SimpleStaticAbility(new NonbasicLandsAreMountainsEffect())); } private MagusOfTheMoon(final MagusOfTheMoon card) { @@ -40,58 +35,4 @@ public final class MagusOfTheMoon extends CardImpl { public MagusOfTheMoon copy() { return new MagusOfTheMoon(this); } - -} - -class MagusOfTheMoonEffect extends ContinuousEffectImpl { - - private static final FilterLandPermanent filter = new FilterLandPermanent(); - - static { - filter.add(Predicates.not(SuperType.BASIC.getPredicate())); - } - - MagusOfTheMoonEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - this.staticText = "Nonbasic lands are Mountains"; - dependendToTypes.add(DependencyType.BecomeNonbasicLand); - dependencyTypes.add(DependencyType.BecomeMountain); - } - - private MagusOfTheMoonEffect(final MagusOfTheMoonEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public MagusOfTheMoonEffect copy() { - return new MagusOfTheMoonEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - switch (layer) { - case TypeChangingEffects_4: - // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects - // So the ability removing has to be done before Layer 6 - land.removeAllAbilities(source.getSourceId(), game); - land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType); - land.addSubType(game, SubType.MOUNTAIN); - // Mountains have the red mana ability intrinsically so the ability must be added in this layer - land.addAbility(new RedManaAbility(), source.getSourceId(), game); - break; - } - } - return true; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.TypeChangingEffects_4; - } } diff --git a/Mage.Sets/src/mage/cards/m/MaiAndZuko.java b/Mage.Sets/src/mage/cards/m/MaiAndZuko.java new file mode 100644 index 00000000000..d25a07f936c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaiAndZuko.java @@ -0,0 +1,57 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.abilities.keyword.FirebendingAbility; +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.FilterCard; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaiAndZuko extends CardImpl { + + private static final FilterCard filter = new FilterCard("Ally spells and artifact spells"); + + static { + filter.add(Predicates.or( + SubType.ALLY.getPredicate(), + CardType.ARTIFACT.getPredicate() + )); + } + + public MaiAndZuko(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Firebending 3 + this.addAbility(new FirebendingAbility(3)); + + // You may cast Ally spells and artifact spells as though they had flash. + this.addAbility(new SimpleStaticAbility(new CastAsThoughItHadFlashAllEffect(Duration.WhileOnBattlefield, filter))); + } + + private MaiAndZuko(final MaiAndZuko card) { + super(card); + } + + @Override + public MaiAndZuko copy() { + return new MaiAndZuko(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaiJadedEdge.java b/Mage.Sets/src/mage/cards/m/MaiJadedEdge.java new file mode 100644 index 00000000000..46a603d6ed9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaiJadedEdge.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.ExhaustAbility; +import mage.abilities.keyword.ProwessAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaiJadedEdge extends CardImpl { + + public MaiJadedEdge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Prowess + this.addAbility(new ProwessAbility()); + + // Exhaust -- {3}: Put a double strike counter on Mai. + this.addAbility(new ExhaustAbility( + new AddCountersSourceEffect(CounterType.DOUBLE_STRIKE.createInstance()), new GenericManaCost(3) + )); + } + + private MaiJadedEdge(final MaiJadedEdge card) { + super(card); + } + + @Override + public MaiJadedEdge copy() { + return new MaiJadedEdge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaiScornfulStriker.java b/Mage.Sets/src/mage/cards/m/MaiScornfulStriker.java new file mode 100644 index 00000000000..6756b0556bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaiScornfulStriker.java @@ -0,0 +1,50 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaiScornfulStriker extends CardImpl { + + public MaiScornfulStriker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Whenever a player casts a noncreature spell, they lose 2 life. + this.addAbility(new SpellCastAllTriggeredAbility( + new LoseLifeTargetEffect(2).setText("they lose 2 life"), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER + )); + } + + private MaiScornfulStriker(final MaiScornfulStriker card) { + super(card); + } + + @Override + public MaiScornfulStriker copy() { + return new MaiScornfulStriker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaladyInvoker.java b/Mage.Sets/src/mage/cards/m/MaladyInvoker.java deleted file mode 100644 index 3a6813d19d4..00000000000 --- a/Mage.Sets/src/mage/cards/m/MaladyInvoker.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; -import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue; -import mage.abilities.dynamicvalue.common.StaticValue; -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.SubType; -import mage.target.common.TargetOpponentsCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MaladyInvoker extends CardImpl { - - private static final DynamicValue xValue = new SignInversionDynamicValue(SourcePermanentPowerValue.NOT_NEGATIVE); - - public MaladyInvoker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.TREEFOLK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.color.setGreen(true); - this.nightCard = true; - - // When this creature transforms into Malady Invoker, target creature an opponent controls gets -0/-X until end of turn, where X is Malady Invoker's power. - Ability ability = new TransformIntoSourceTriggeredAbility(new BoostTargetEffect( - StaticValue.get(0), xValue, Duration.EndOfTurn - ).setText("target creature an opponent controls gets -0/-X until end of turn, where X is {this}'s power")); - ability.addTarget(new TargetOpponentsCreaturePermanent()); - this.addAbility(ability); - } - - private MaladyInvoker(final MaladyInvoker card) { - super(card); - } - - @Override - public MaladyInvoker copy() { - return new MaladyInvoker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MalevolentHermit.java b/Mage.Sets/src/mage/cards/m/MalevolentHermit.java index 85c609a4651..3ab9ba10c19 100644 --- a/Mage.Sets/src/mage/cards/m/MalevolentHermit.java +++ b/Mage.Sets/src/mage/cards/m/MalevolentHermit.java @@ -1,16 +1,19 @@ package mage.cards.m; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.TargetSpell; @@ -20,16 +23,17 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MalevolentHermit extends CardImpl { +public final class MalevolentHermit extends TransformingDoubleFacedCard { public MalevolentHermit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{U}", + "Benevolent Geist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WIZARD}, "U" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.b.BenevolentGeist.class; + // Malevolent Hermit + this.getLeftHalfCard().setPT(2, 1); // {U}, Sacrifice Malevolent Hermit: Counter target noncreature spell unless its controller pays {3}. Ability ability = new SimpleActivatedAbility( @@ -37,10 +41,24 @@ public final class MalevolentHermit extends CardImpl { ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Disturb {2}{U} - this.addAbility(new DisturbAbility(this, "{2}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{U}")); + + // Benevolent Geist + this.getRightHalfCard().setPT(2, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Noncreature spells you control can't be countered. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect( + StaticFilters.FILTER_SPELLS_NON_CREATURE, Duration.WhileOnBattlefield + ))); + + // If Benevolent Geist would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private MalevolentHermit(final MalevolentHermit card) { diff --git a/Mage.Sets/src/mage/cards/m/MaliciousInvader.java b/Mage.Sets/src/mage/cards/m/MaliciousInvader.java deleted file mode 100644 index a86263bc19f..00000000000 --- a/Mage.Sets/src/mage/cards/m/MaliciousInvader.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.OpponentControlsPermanentCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -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.TargetController; -import mage.filter.FilterPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MaliciousInvader extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(SubType.HUMAN, "an opponent controls a Human"); - - private static final Condition condition = new OpponentControlsPermanentCondition(filter); - private static final Hint hint = new ConditionHint(condition, "An opponent controls a Human"); - - public MaliciousInvader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Malicious Invader gets +2/+0 as long as an opponent controls a Human. - this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( - new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield), - condition, "{this} gets +2/+0 as long as an opponent controls a Human" - )).addHint(hint)); - } - - private MaliciousInvader(final MaliciousInvader card) { - super(card); - } - - @Override - public MaliciousInvader copy() { - return new MaliciousInvader(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/Manabarbs.java b/Mage.Sets/src/mage/cards/m/Manabarbs.java index 2ce7acb564f..d267a2cbd21 100644 --- a/Mage.Sets/src/mage/cards/m/Manabarbs.java +++ b/Mage.Sets/src/mage/cards/m/Manabarbs.java @@ -22,7 +22,7 @@ public final class Manabarbs extends CardImpl { // Whenever a player taps a land for mana, Manabarbs deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), new FilterLandPermanent("a player taps a land"), SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/m/ManticoreOfTheGauntlet.java b/Mage.Sets/src/mage/cards/m/ManticoreOfTheGauntlet.java index 53ecb2e7186..60611147a48 100644 --- a/Mage.Sets/src/mage/cards/m/ManticoreOfTheGauntlet.java +++ b/Mage.Sets/src/mage/cards/m/ManticoreOfTheGauntlet.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.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -37,7 +35,7 @@ public final class ManticoreOfTheGauntlet extends CardImpl { counters.setText("put a -1/-1 counter on target creature you control"); counters.setTargetPointer(new FirstTargetPointer()); - Effect damage = new DamageTargetEffect(StaticValue.get(3), true, "", true); + Effect damage = new DamageTargetEffect(3); damage.setText("{this} deals 3 damage to target opponent or planeswalker."); damage.setTargetPointer(new SecondTargetPointer()); diff --git a/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java b/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java deleted file mode 100644 index 37cea498d81..00000000000 --- a/Mage.Sets/src/mage/cards/m/MarchesaResoluteMonarch.java +++ /dev/null @@ -1,122 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.WatcherScope; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; -import mage.target.TargetPermanent; -import mage.watchers.Watcher; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MarchesaResoluteMonarch extends CardImpl { - - public MarchesaResoluteMonarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(3); - this.toughness = new MageInt(6); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Deathtouch - this.addAbility(DeathtouchAbility.getInstance()); - - // Whenever Marchesa, Resolute Monarch attacks, remove all counters from up to one target permanent. - Ability ability = new AttacksTriggeredAbility(new RemoveAllCountersPermanentTargetEffect()); - ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT)); - this.addAbility(ability); - - // At the beginning of your upkeep, if you haven't been dealt combat damage since your last turn, you draw a card and you lose 1 life. - ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1, true)) - .withInterveningIf(MarchesaResoluteMonarchCondition.instance); - ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private MarchesaResoluteMonarch(final MarchesaResoluteMonarch card) { - super(card); - } - - @Override - public MarchesaResoluteMonarch copy() { - return new MarchesaResoluteMonarch(this); - } - - public static MarchesaResoluteMonarchWatcher makeWatcher() { - return new MarchesaResoluteMonarchWatcher(); - } -} - -enum MarchesaResoluteMonarchCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return MarchesaResoluteMonarchWatcher.checkPlayer(game, source); - } - - @Override - public String toString() { - return "you haven't been dealt combat damage since your last turn"; - } -} - -class MarchesaResoluteMonarchWatcher extends Watcher { - - private final Set players = new HashSet<>(); - - MarchesaResoluteMonarchWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - switch (event.getType()) { - case DAMAGED_PLAYER: - if (((DamagedEvent) event).isCombatDamage()) { - players.add(event.getTargetId()); - } - return; - case END_TURN_STEP_POST: - players.remove(game.getActivePlayerId()); - return; - - } - } - - static boolean checkPlayer(Game game, Ability source) { - return !game - .getState() - .getWatcher(MarchesaResoluteMonarchWatcher.class) - .players - .contains(source.getControllerId()); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MarkovsServant.java b/Mage.Sets/src/mage/cards/m/MarkovsServant.java deleted file mode 100644 index 81a62c53563..00000000000 --- a/Mage.Sets/src/mage/cards/m/MarkovsServant.java +++ /dev/null @@ -1,36 +0,0 @@ - -package mage.cards.m; - -import java.util.UUID; -import mage.MageInt; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Loki - */ -public final class MarkovsServant extends CardImpl { - - public MarkovsServant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},null); - this.subtype.add(SubType.VAMPIRE); - this.color.setBlack(true); - - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.nightCard = true; - } - - private MarkovsServant(final MarkovsServant card) { - super(card); - } - - @Override - public MarkovsServant copy() { - return new MarkovsServant(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java index b4d4df12080..4c33ac837a6 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java @@ -24,7 +24,7 @@ public final class MaskOfIntolerance extends CardImpl { // 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. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(3, true, "that player"), false + TargetController.EACH_PLAYER, new DamageTargetEffect(3).withTargetDescription("that player"), false ).withInterveningIf(MaskOfIntoleranceCondition.instance).addHint(DomainHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/m/MasterPakku.java b/Mage.Sets/src/mage/cards/m/MasterPakku.java index 2ee107fed73..98eb78240ab 100644 --- a/Mage.Sets/src/mage/cards/m/MasterPakku.java +++ b/Mage.Sets/src/mage/cards/m/MasterPakku.java @@ -3,11 +3,10 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.MillCardsTargetEffect; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; import mage.abilities.keyword.ProwessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,7 +24,6 @@ import java.util.UUID; public final class MasterPakku extends CardImpl { private static final DynamicValue xValue = new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON, "Lesson cards"), null); - private static final Hint hint = new ValueHint("Lesson cards in your graveyard", xValue); public MasterPakku(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); @@ -43,7 +41,7 @@ public final class MasterPakku extends CardImpl { // Whenever Master Pakku becomes tapped, target player mills X cards, where X is the number of Lesson cards in your graveyard. Ability ability = new BecomesTappedSourceTriggeredAbility(new MillCardsTargetEffect(xValue)); ability.addTarget(new TargetPlayer()); - this.addAbility(ability.addHint(hint)); + this.addAbility(ability.addHint(LessonsInGraveCondition.getHint())); } private MasterPakku(final MasterPakku card) { diff --git a/Mage.Sets/src/mage/cards/m/MastercraftRaptor.java b/Mage.Sets/src/mage/cards/m/MastercraftRaptor.java deleted file mode 100644 index f24de42eba0..00000000000 --- a/Mage.Sets/src/mage/cards/m/MastercraftRaptor.java +++ /dev/null @@ -1,88 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.ExileZone; -import mage.game.Game; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MastercraftRaptor extends CardImpl { - - public MastercraftRaptor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setRed(true); - - // Mastercraft Raptor's power is equal to the total power of the exiled cards used to craft it. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SetBasePowerSourceEffect(MastercraftRaptorValue.instance) - .setText("{this}'s power is equal to the total power of the exiled cards used to craft it") - )); - } - - private MastercraftRaptor(final MastercraftRaptor card) { - super(card); - } - - @Override - public MastercraftRaptor copy() { - return new MastercraftRaptor(this); - } -} - -enum MastercraftRaptorValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, sourceAbility.getSourceId(), - game.getState().getZoneChangeCounter(sourceAbility.getSourceId()) - 2 - )); - if (exileZone == null) { - return 0; - } - return exileZone - .getCards(game) - .stream() - .map(MageObject::getPower) - .mapToInt(MageInt::getValue) - .sum(); - } - - @Override - public MastercraftRaptorValue copy() { - return this; - } - - @Override - public String getMessage() { - return ""; - } - - @Override - public String toString() { - return "1"; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MastersGuidance.java b/Mage.Sets/src/mage/cards/m/MastersGuidance.java new file mode 100644 index 00000000000..bab0517611a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MastersGuidance.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.common.FerociousHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetAttackingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MastersGuidance extends CardImpl { + + public MastersGuidance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // Whenever you attack with two or more legendary creatures, put a +1/+1 counter on each of up to two target attacking creatures. + Ability ability = new AttacksWithCreaturesTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + 2, StaticFilters.FILTER_CREATURES_LEGENDARY + ); + ability.addTarget(new TargetAttackingCreature(0, 2)); + this.addAbility(ability); + + // At the beginning of your end step, if you control a creature with power 4 or greater, draw a card. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(FerociousCondition.instance) + .addHint(FerociousHint.instance)); + } + + private MastersGuidance(final MastersGuidance card) { + super(card); + } + + @Override + public MastersGuidance copy() { + return new MastersGuidance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MastersGuideMural.java b/Mage.Sets/src/mage/cards/m/MastersGuideMural.java index b53450a195c..47afffa7ba5 100644 --- a/Mage.Sets/src/mage/cards/m/MastersGuideMural.java +++ b/Mage.Sets/src/mage/cards/m/MastersGuideMural.java @@ -1,29 +1,56 @@ package mage.cards.m; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.game.permanent.token.GolemWhiteBlueToken; +import mage.watchers.Watcher; -import java.util.UUID; +import java.util.*; /** * @author Susucr */ -public final class MastersGuideMural extends CardImpl { +public final class MastersGuideMural extends TransformingDoubleFacedCard { public MastersGuideMural(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{W}{U}"); - this.secondSideCardClazz = mage.cards.m.MastersManufactory.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}{W}{U}", + "Master's Manufactory", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "WU" + ); + // Master's Guide-Mural // When Master's Guide-Mural enters the battlefield, create a 4/4 white and blue Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemWhiteBlueToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemWhiteBlueToken()))); // Craft with artifact {4}{W}{W}{U} - this.addAbility(new CraftAbility("{4}{W}{W}{U}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{4}{W}{W}{U}")); + + // Master's Manufactory + // {T}: Create a 4/4 white and blue Golem artifact creature token. Activate only if Master's Manufactory or another artifact entered the battlefield under your control this turn. + Ability ability = new ActivateIfConditionActivatedAbility( + new CreateTokenEffect(new GolemWhiteBlueToken()), new TapSourceCost(), MastersManufactoryCondition.instance + ); + ability.addHint(MastersManufactoryCondition.getHint()); + ability.addWatcher(new MastersManufactoryWatcher()); + this.getRightHalfCard().addAbility(ability); } private MastersGuideMural(final MastersGuideMural card) { @@ -35,3 +62,60 @@ public final class MastersGuideMural extends CardImpl { return new MastersGuideMural(this); } } + +enum MastersManufactoryCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + MastersManufactoryWatcher watcher = game.getState().getWatcher(MastersManufactoryWatcher.class); + return watcher != null && permanent != null + && watcher.check(source.getControllerId(), new MageObjectReference(permanent, game)); + } + + @Override + public String toString() { + return "{this} or another artifact entered the battlefield under your control this turn"; + } +} + +class MastersManufactoryWatcher extends Watcher { + + private final Set playerHadArtifactEnter = new HashSet<>(); + private final Map> allEnteredThisTurn = new HashMap<>(); + + MastersManufactoryWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent.isArtifact(game)) { + playerHadArtifactEnter.add(event.getPlayerId()); + } + allEnteredThisTurn + .computeIfAbsent(event.getPlayerId(), k -> new HashSet<>()) + .add(new MageObjectReference(permanent, game)); + } + } + + @Override + public void reset() { + super.reset(); + playerHadArtifactEnter.clear(); + allEnteredThisTurn.clear(); + } + + boolean check(UUID playerId, MageObjectReference mor) { + return playerHadArtifactEnter.contains(playerId) + || allEnteredThisTurn.getOrDefault(playerId, Collections.emptySet()).contains(mor); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MastersManufactory.java b/Mage.Sets/src/mage/cards/m/MastersManufactory.java deleted file mode 100644 index ed3f49799fa..00000000000 --- a/Mage.Sets/src/mage/cards/m/MastersManufactory.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.m; - -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.CreateTokenEffect; -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.WatcherScope; -import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.GolemWhiteBlueToken; -import mage.watchers.Watcher; - -import java.util.*; - -/** - * @author Susucr - */ -public final class MastersManufactory extends CardImpl { - - public MastersManufactory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - this.color.setBlue(true); - this.color.setWhite(true); - - // {T}: Create a 4/4 white and blue Golem artifact creature token. Activate only if Master's Manufactory or another artifact entered the battlefield under your control this turn. - this.addAbility(new ActivateIfConditionActivatedAbility( - new CreateTokenEffect(new GolemWhiteBlueToken()), - new TapSourceCost(), MastersManufactoryCondition.instance - ).addHint(MastersManufactoryCondition.getHint()), new MastersManufactoryWatcher()); - } - - private MastersManufactory(final MastersManufactory card) { - super(card); - } - - @Override - public MastersManufactory copy() { - return new MastersManufactory(this); - } -} - -enum MastersManufactoryCondition implements Condition { - instance; - private static final Hint hint = new ConditionHint(instance); - - public static Hint getHint() { - return hint; - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - MastersManufactoryWatcher watcher = game.getState().getWatcher(MastersManufactoryWatcher.class); - return watcher != null && permanent != null - && watcher.check(source.getControllerId(), new MageObjectReference(permanent, game)); - } - - @Override - public String toString() { - return "{this} or another artifact entered the battlefield under your control this turn"; - } -} - -class MastersManufactoryWatcher extends Watcher { - - // player -> an artifact entered this turn - private final Set playerHadArtifactEnter = new HashSet<>(); - // We need to store a lot for edges cases: - // -> Master's Manufactory could have entered as a non-artifact - // -> Another permanent could gain Manufactory's ability (copy effect), and we need to have tracked if it entered - // player -> set of all MOR of permanents that entered this turn under that player's control - private final Map> allEnteredThisTurn = new HashMap<>(); - - MastersManufactoryWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { - Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - if (permanent.isArtifact(game)) { - playerHadArtifactEnter.add(event.getPlayerId()); - } - allEnteredThisTurn - .computeIfAbsent(event.getPlayerId(), k -> new HashSet<>()) - .add(new MageObjectReference(permanent, game)); - } - } - - @Override - public void reset() { - super.reset(); - playerHadArtifactEnter.clear(); - allEnteredThisTurn.clear(); - } - - boolean check(UUID playerId, MageObjectReference mor) { - return playerHadArtifactEnter.contains(playerId) - || allEnteredThisTurn.getOrDefault(playerId, Collections.emptySet()).contains(mor); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java b/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java index 04f0ff0b214..2bd9cba7af3 100644 --- a/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java +++ b/Mage.Sets/src/mage/cards/m/MatzalantliTheGreatDoor.java @@ -1,23 +1,25 @@ package mage.cards.m; +import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.IntCompareCondition; +import mage.abilities.condition.common.DescendCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -28,29 +30,40 @@ import java.util.stream.Collectors; /** * @author Susucr */ -public final class MatzalantliTheGreatDoor extends CardImpl { +public final class MatzalantliTheGreatDoor extends TransformingDoubleFacedCard { private static final Hint hint = new ValueHint("Permanent types in graveyard", MatzalantliTheGreatDoorValue.instance); + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENT); public MatzalantliTheGreatDoor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - this.secondSideCardClazz = mage.cards.t.TheCore.class; - - this.supertype.add(SuperType.LEGENDARY); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "The Core", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Matzalantli, the Great Door // {T}: Draw a card, then discard a card. - this.addAbility(new SimpleActivatedAbility(new DrawDiscardControllerEffect(), new TapSourceCost())); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new DrawDiscardControllerEffect(), new TapSourceCost())); // {4}, {T}: Transform Matzalantli, the Great Door. Activate only if there are four or more permanent types among cards in your graveyard. - this.addAbility(new TransformAbility()); Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), - new GenericManaCost(4), - new MatzalantliTheGreatDoorCondition() + new TransformSourceEffect(), new GenericManaCost(4), new MatzalantliTheGreatDoorCondition() ); ability.addCost(new TapSourceCost()); ability.addHint(hint); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // The Core + // Fathomless descent -- {T}: Add X mana of any one color, where X is the number of permanent cards in your graveyard. + this.getRightHalfCard().addSuperType(SuperType.LEGENDARY); + Ability manaAbility = new DynamicManaAbility( + Mana.AnyMana(1), xValue, new TapSourceCost(), + "Add X mana of any one color, where X is the number of permanent cards in your graveyard.", true + ); + manaAbility.setAbilityWord(AbilityWord.FATHOMLESS_DESCENT); + manaAbility.addHint(DescendCondition.getHint()); + this.getRightHalfCard().addAbility(manaAbility); } private MatzalantliTheGreatDoor(final MatzalantliTheGreatDoor card) { @@ -83,9 +96,6 @@ class MatzalantliTheGreatDoorCondition extends IntCompareCondition { enum MatzalantliTheGreatDoorValue implements DynamicValue { instance; - MatzalantliTheGreatDoorValue() { - } - @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { Player controller = game.getPlayer(sourceAbility.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/m/MayorOfAvabruck.java b/Mage.Sets/src/mage/cards/m/MayorOfAvabruck.java index f9f11c93350..460350bce16 100644 --- a/Mage.Sets/src/mage/cards/m/MayorOfAvabruck.java +++ b/Mage.Sets/src/mage/cards/m/MayorOfAvabruck.java @@ -1,49 +1,66 @@ package mage.cards.m; -import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.WolfToken; import java.util.UUID; /** * @author North, noxx */ -public final class MayorOfAvabruck extends CardImpl { +public final class MayorOfAvabruck extends TransformingDoubleFacedCard { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Human creatures"); + private static final FilterCreaturePermanent howlpackFilter = new FilterCreaturePermanent("each other creature you control that's a Werewolf or a Wolf"); static { filter.add(SubType.HUMAN.getPredicate()); + howlpackFilter.add(Predicates.or(SubType.WEREWOLF.getPredicate(), SubType.WOLF.getPredicate())); } public MayorOfAvabruck(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ADVISOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ADVISOR, SubType.WEREWOLF}, "{1}{G}", + "Howlpack Alpha", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.h.HowlpackAlpha.class; - - this.power = new MageInt(1); - this.toughness = new MageInt(1); + // Mayor of Avabruck + this.getLeftHalfCard().setPT(1, 1); // Other Human creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( 1, 1, Duration.WhileOnBattlefield, filter, true ))); // At the beginning of each upkeep, if no spells were cast last turn, transform Mayor of Avabruck. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Howlpack Alpha + this.getRightHalfCard().setPT(3, 3); + + // Other Werewolf and Wolf creatures you control get +1/+1. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, howlpackFilter, true + ))); + + // At the beginning of your end step, create a 2/2 green Wolf creature token. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new WolfToken()))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Howlpack Alpha. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private MayorOfAvabruck(final MayorOfAvabruck card) { diff --git a/Mage.Sets/src/mage/cards/m/MazirekKraulDeathPriest.java b/Mage.Sets/src/mage/cards/m/MazirekKraulDeathPriest.java index 111ba402199..8d458e37df1 100644 --- a/Mage.Sets/src/mage/cards/m/MazirekKraulDeathPriest.java +++ b/Mage.Sets/src/mage/cards/m/MazirekKraulDeathPriest.java @@ -6,28 +6,22 @@ import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.FlyingAbility; 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.constants.TargetController; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; /** - * * @author fireshoes */ public final class MazirekKraulDeathPriest extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public MazirekKraulDeathPriest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.SHAMAN); @@ -38,9 +32,9 @@ public final class MazirekKraulDeathPriest extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever a player sacrifices another permanent, put a +1/+1 counter on each creature you control. - this.addAbility(new SacrificePermanentTriggeredAbility(Zone.BATTLEFIELD, - new AddCountersAllEffect(CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE), - filter, TargetController.ANY, SetTargetPointer.NONE, false)); + this.addAbility(new SacrificePermanentTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ), StaticFilters.FILTER_ANOTHER_PERMANENT, TargetController.ANY)); } private MazirekKraulDeathPriest(final MazirekKraulDeathPriest card) { diff --git a/Mage.Sets/src/mage/cards/m/MeatLockerDrownedDiner.java b/Mage.Sets/src/mage/cards/m/MeatLockerDrownedDiner.java new file mode 100644 index 00000000000..32bd8fcfc08 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MeatLockerDrownedDiner.java @@ -0,0 +1,46 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MeatLockerDrownedDiner extends RoomCard { + + public MeatLockerDrownedDiner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{U}", "{3}{U}{U}"); + + // Meat Locker + // When you unlock this door, tap up to one target creature and put two stun counters on it. + Ability ability = new UnlockThisDoorTriggeredAbility(new TapTargetEffect(), false, true); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance(2)) + .setText("and put two stun counters on it")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.getLeftHalfCard().addAbility(ability); + + // Drowned Diner + // When you unlock this door, draw three cards, then discard a card. + this.getRightHalfCard().addAbility(new UnlockThisDoorTriggeredAbility( + new DrawDiscardControllerEffect(3, 1), false, false + )); + } + + private MeatLockerDrownedDiner(final MeatLockerDrownedDiner card) { + super(card); + } + + @Override + public MeatLockerDrownedDiner copy() { + return new MeatLockerDrownedDiner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeditationPools.java b/Mage.Sets/src/mage/cards/m/MeditationPools.java new file mode 100644 index 00000000000..922f521ad82 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MeditationPools.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +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.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MeditationPools extends CardImpl { + + public MeditationPools(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {G} or {U}. + this.addAbility(new GreenManaAbility()); + this.addAbility(new BlueManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private MeditationPools(final MeditationPools card) { + super(card); + } + + @Override + public MeditationPools copy() { + return new MeditationPools(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MegaFlare.java b/Mage.Sets/src/mage/cards/m/MegaFlare.java new file mode 100644 index 00000000000..05f945b2d05 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MegaFlare.java @@ -0,0 +1,53 @@ +package mage.cards.m; + +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.KickerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.UtvaraHellkiteDragonToken; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.ForEachPlayerTargetsAdjuster; +import mage.target.targetpointer.EachTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MegaFlare extends CardImpl { + + public MegaFlare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Kicker {3}{R}{R} + this.addAbility(new KickerAbility("{3}{R}{R}")); + + // If this spell was kicked, create a 6/6 red Dragon creature token with flying. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new CreateTokenEffect(new UtvaraHellkiteDragonToken()), KickedCondition.ONCE, + "if this spell was kicked, create a 6/6 red Dragon creature token with flying" + )); + + // For each opponent, choose up to one target creature that player controls. Mega Flare deals damage equal to the greatest power among creatures you control to each of the chosen creatures. + this.getSpellAbility().addEffect(new DamageTargetEffect(GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES) + .setText("
For each opponent, choose up to one target creature that player controls. " + + "{this} deals damage equal to the greatest power among creatures you control " + + "to each of the chosen creatures").setTargetPointer(new EachTargetPointer())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + this.getSpellAbility().setTargetAdjuster(new ForEachPlayerTargetsAdjuster(false, true)); + } + + private MegaFlare(final MegaFlare card) { + super(card); + } + + @Override + public MegaFlare copy() { + return new MegaFlare(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MegatronDestructiveForce.java b/Mage.Sets/src/mage/cards/m/MegatronDestructiveForce.java deleted file mode 100644 index 7b718d6efbd..00000000000 --- a/Mage.Sets/src/mage/cards/m/MegatronDestructiveForce.java +++ /dev/null @@ -1,147 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.StaticHint; -import mage.abilities.keyword.LivingMetalAbility; -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.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetSacrifice; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class MegatronDestructiveForce extends CardImpl { - public MegatronDestructiveForce(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Whenever Megatron attacks, you may sacrifice another artifact. When you do, Megatron deals damage equal to the sacrificed artifact's mana value to target creature. If excess damage would be dealt to that creature this way, instead that damage is dealt to that creature's controller and you convert Megatron. - this.addAbility(new AttacksTriggeredAbility(new MegatronDestructiveForceEffect())); - } - - private MegatronDestructiveForce(final MegatronDestructiveForce card) { - super(card); - } - - @Override - public MegatronDestructiveForce copy() { - return new MegatronDestructiveForce(this); - } -} - -class MegatronDestructiveForceEffect extends OneShotEffect { - - MegatronDestructiveForceEffect() { - super(Outcome.Benefit); - staticText = "you may sacrifice another artifact. When you do, {this} deals damage equal to the sacrificed artifact's mana value to target creature. If excess damage would be dealt to that creature this way, instead that damage is dealt to that creature's controller and you convert {this}."; - } - - private MegatronDestructiveForceEffect(final MegatronDestructiveForceEffect effect) { - super(effect); - } - - @Override - public MegatronDestructiveForceEffect copy() { - return new MegatronDestructiveForceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetSacrifice target = new TargetSacrifice( - 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_ARTIFACT - ); - player.choose(outcome, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent == null) { - return false; - } - - int manaValue = Math.max(permanent.getManaValue(), 0); - if (!permanent.sacrifice(source, game)) { - return false; - } - - ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new MegatronDestructiveForceReflexiveEffect(manaValue), false - ); - ability.addHint(new StaticHint("Sacrificed artifact mana value: " + manaValue)); - ability.addTarget(new TargetCreaturePermanent()); - game.fireReflexiveTriggeredAbility(ability, source); - return true; - } -} - -class MegatronDestructiveForceReflexiveEffect extends OneShotEffect { - - private final int value; - - MegatronDestructiveForceReflexiveEffect(int value) { - super(Outcome.Damage); - staticText = "{this} deals damage equal to the sacrificed artifact's mana value to target " + - "creature. If excess damage would be dealt to that creature this way, instead that damage " + - "is dealt to that creature's controller and you convert {this}."; - this.value = value; - } - - private MegatronDestructiveForceReflexiveEffect(final MegatronDestructiveForceReflexiveEffect effect) { - super(effect); - this.value = effect.value; - } - - @Override - public MegatronDestructiveForceReflexiveEffect copy() { - return new MegatronDestructiveForceReflexiveEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (value < 1) { - return false; - } - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - int excess = permanent.damageWithExcess(value, source, game); - if (excess < 1) { - return true; - } - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(excess, source, game); - } - new TransformSourceEffect().apply(game, source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MegatronTyrant.java b/Mage.Sets/src/mage/cards/m/MegatronTyrant.java index 967a92f1f22..93aabd1b4a5 100644 --- a/Mage.Sets/src/mage/cards/m/MegatronTyrant.java +++ b/Mage.Sets/src/mage/cards/m/MegatronTyrant.java @@ -1,44 +1,54 @@ package mage.cards.m; -import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.dynamicvalue.common.OpponentsLostLifeCount; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.mana.DynamicManaEffect; +import mage.abilities.hint.StaticHint; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetSacrifice; import java.util.UUID; /** * @author Susucr */ -public final class MegatronTyrant extends CardImpl { +public final class MegatronTyrant extends TransformingDoubleFacedCard { public MegatronTyrant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{R}{W}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{3}{R}{W}{B}", + "Megatron, Destructive Force", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "RWB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(7); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.m.MegatronDestructiveForce.class; + // Megatron, Tyrant + this.getLeftHalfCard().setPT(7, 5); // More Than Meets the Eye {1}{R}{W}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{1}{R}{W}{B}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{1}{R}{W}{B}")); // Your opponents can't cast spells during combat. - this.addAbility(new SimpleStaticAbility(new MegatronTyrantCantCastSpellsEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new MegatronTyrantCantCastSpellsEffect())); // At the beginning of your postcombat main phase, you may convert Megatron. If you do, add {C} for each 1 life your opponents have lost this turn. TriggeredAbility trigger = new BeginningOfPostcombatMainTriggeredAbility( @@ -46,14 +56,22 @@ public final class MegatronTyrant extends CardImpl { true ); trigger.addEffect( - new DynamicManaEffect( - Mana.ColorlessMana(1), - OpponentsLostLifeCount.instance, - "add {C} for each 1 life your opponents have lost this turn" - ).concatBy("If you do,") + new DynamicManaEffect( + Mana.ColorlessMana(1), + OpponentsLostLifeCount.instance, + "add {C} for each 1 life your opponents have lost this turn" + ).concatBy("If you do,") ); + this.getLeftHalfCard().addAbility(trigger); - this.addAbility(trigger); + // Megatron, Destructive Force + this.getRightHalfCard().setPT(4, 5); + + // Living Metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Whenever Megatron attacks, you may sacrifice another artifact. When you do, Megatron deals damage equal to the sacrificed artifact's mana value to target creature. If excess damage would be dealt to that creature this way, instead that damage is dealt to that creature's controller and you convert Megatron. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new MegatronDestructiveForceEffect())); } private MegatronTyrant(final MegatronTyrant card) { @@ -99,7 +117,98 @@ class MegatronTyrantCantCastSpellsEffect extends ContinuousRuleModifyingEffectIm @Override public boolean applies(GameEvent event, Ability source, Game game) { return game.getOpponents(source.getControllerId()).contains(event.getPlayerId()) - && game.getTurnPhaseType() == TurnPhase.COMBAT; + && game.getTurnPhaseType() == TurnPhase.COMBAT; + } +} + +class MegatronDestructiveForceEffect extends OneShotEffect { + + MegatronDestructiveForceEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice another artifact. When you do, {this} deals damage equal to the sacrificed artifact's mana value " + + "to target creature. If excess damage would be dealt to that creature this way, instead that damage is dealt to that creature's controller " + + "and you convert {this}."; } + private MegatronDestructiveForceEffect(final MegatronDestructiveForceEffect effect) { + super(effect); + } + + @Override + public MegatronDestructiveForceEffect copy() { + return new MegatronDestructiveForceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetSacrifice target = new TargetSacrifice( + 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_ARTIFACT + ); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + return false; + } + + int manaValue = Math.max(permanent.getManaValue(), 0); + if (!permanent.sacrifice(source, game)) { + return false; + } + + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new MegatronDestructiveForceReflexiveEffect(manaValue), false + ); + ability.addHint(new StaticHint("Sacrificed artifact mana value: " + manaValue)); + ability.addTarget(new TargetCreaturePermanent()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} + +class MegatronDestructiveForceReflexiveEffect extends OneShotEffect { + + private final int value; + + MegatronDestructiveForceReflexiveEffect(int value) { + super(Outcome.Damage); + staticText = "{this} deals damage equal to the sacrificed artifact's mana value to target " + + "creature. If excess damage would be dealt to that creature this way, instead that damage " + + "is dealt to that creature's controller and you convert {this}."; + this.value = value; + } + + private MegatronDestructiveForceReflexiveEffect(final MegatronDestructiveForceReflexiveEffect effect) { + super(effect); + this.value = effect.value; + } + + @Override + public MegatronDestructiveForceReflexiveEffect copy() { + return new MegatronDestructiveForceReflexiveEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (value < 1) { + return false; + } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + int excess = permanent.damageWithExcess(value, source, game); + if (excess < 1) { + return true; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.damage(excess, source, game); + } + new TransformSourceEffect().apply(game, source); + return true; + } } diff --git a/Mage.Sets/src/mage/cards/m/Megrim.java b/Mage.Sets/src/mage/cards/m/Megrim.java index 4f2d3aec0ca..a258655a852 100644 --- a/Mage.Sets/src/mage/cards/m/Megrim.java +++ b/Mage.Sets/src/mage/cards/m/Megrim.java @@ -19,7 +19,7 @@ public final class Megrim extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}"); // Whenever an opponent discards a card, Megrim deals 2 damage to that player. - this.addAbility(new DiscardsACardOpponentTriggeredAbility(new DamageTargetEffect(2, true, "that player"), false, SetTargetPointer.PLAYER)); + this.addAbility(new DiscardsACardOpponentTriggeredAbility(new DamageTargetEffect(2).withTargetDescription("that player"), false, SetTargetPointer.PLAYER)); } private Megrim(final Megrim card) { diff --git a/Mage.Sets/src/mage/cards/m/MemoryOfToshiro.java b/Mage.Sets/src/mage/cards/m/MemoryOfToshiro.java deleted file mode 100644 index 31ad7b29957..00000000000 --- a/Mage.Sets/src/mage/cards/m/MemoryOfToshiro.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.costs.common.PayLifeCost; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MemoryOfToshiro extends CardImpl { - - public MemoryOfToshiro(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SAMURAI); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // {T}, Pay 1 life: Add {B}. Spend this mana only to cast an instant or sorcery spell. - Ability ability = new ConditionalColoredManaAbility(Mana.BlackMana(1), new InstantOrSorcerySpellManaBuilder()); - ability.addCost(new PayLifeCost(1)); - this.addAbility(ability); - } - - private MemoryOfToshiro(final MemoryOfToshiro card) { - super(card); - } - - @Override - public MemoryOfToshiro copy() { - return new MemoryOfToshiro(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MercilessPredator.java b/Mage.Sets/src/mage/cards/m/MercilessPredator.java deleted file mode 100644 index 9ea43ac8cd2..00000000000 --- a/Mage.Sets/src/mage/cards/m/MercilessPredator.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class MercilessPredator extends CardImpl { - - public MercilessPredator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Merciless Predator. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private MercilessPredator(final MercilessPredator card) { - super(card); - } - - @Override - public MercilessPredator copy() { - return new MercilessPredator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MessengerHawk.java b/Mage.Sets/src/mage/cards/m/MessengerHawk.java new file mode 100644 index 00000000000..a3255377265 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MessengerHawk.java @@ -0,0 +1,55 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DrewTwoOrMoreCardsCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; +import mage.abilities.effects.common.CreateTokenEffect; +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.Duration; +import mage.constants.SubType; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MessengerHawk extends CardImpl { + + public MessengerHawk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/B}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this creature enters, create a Clue token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + + // This creature gets +2/+0 as long as you've drawn two or more cards this turn. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield), + DrewTwoOrMoreCardsCondition.instance, "{this} gets +2/+0 as long as you've drawn two or more cards this turn" + )).addHint(CardsDrawnThisTurnDynamicValue.getHint())); + } + + private MessengerHawk(final MessengerHawk card) { + super(card); + } + + @Override + public MessengerHawk copy() { + return new MessengerHawk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeteorSword.java b/Mage.Sets/src/mage/cards/m/MeteorSword.java new file mode 100644 index 00000000000..86f5114ff80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MeteorSword.java @@ -0,0 +1,47 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +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.SubType; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MeteorSword extends CardImpl { + + public MeteorSword(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{7}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When this Equipment enters, destroy target permanent. + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + + // Equipped creature gets +3/+3. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(3, 3))); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private MeteorSword(final MeteorSword card) { + super(card); + } + + @Override + public MeteorSword copy() { + return new MeteorSword(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java deleted file mode 100644 index 8ff50743a8a..00000000000 --- a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.m; - -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.effects.common.DamagePlayersEffect; -import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.util.RandomUtil; -import mage.watchers.common.AttackedThisTurnWatcher; - -import java.util.Objects; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author LevelX2 - */ -public final class MetzaliTowerOfTriumph extends CardImpl { - - public MetzaliTowerOfTriumph(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // (Transforms from Path of Mettle.) - - // {t}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - - // {1}{R}, {T}: Metzali, Tower of Triumph deals 2 damage to each opponent. - Ability ability = new SimpleActivatedAbility(new DamagePlayersEffect(2, TargetController.OPPONENT), new ManaCostsImpl<>("{1}{R}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - - // {2}{W}, {T}: Choose a creature at random that attacked this turn. Destroy that creature. - ability = new SimpleActivatedAbility(new MetzaliTowerOfTriumphEffect(), new ManaCostsImpl<>("{2}{W}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private MetzaliTowerOfTriumph(final MetzaliTowerOfTriumph card) { - super(card); - } - - @Override - public MetzaliTowerOfTriumph copy() { - return new MetzaliTowerOfTriumph(this); - } - -} - -class MetzaliTowerOfTriumphEffect extends OneShotEffect { - - MetzaliTowerOfTriumphEffect() { - super(Outcome.DestroyPermanent); - this.staticText = "choose a creature at random that attacked this turn. Destroy that creature"; - } - - private MetzaliTowerOfTriumphEffect(final MetzaliTowerOfTriumphEffect effect) { - super(effect); - } - - @Override - public MetzaliTowerOfTriumphEffect copy() { - return new MetzaliTowerOfTriumphEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = RandomUtil.randomFromCollection( - game.getState() - .getWatcher(AttackedThisTurnWatcher.class) - .getAttackedThisTurnCreatures() - .stream() - .map(mor -> mor.getPermanent(game)) - .filter(Objects::nonNull) - .collect(Collectors.toSet()) - ); - return permanent != null && permanent.destroy(source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MichelangeloTheHeart.java b/Mage.Sets/src/mage/cards/m/MichelangeloTheHeart.java new file mode 100644 index 00000000000..b3688fc86dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MichelangeloTheHeart.java @@ -0,0 +1,62 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.condition.common.RaidCondition; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.common.RaidHint; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfSecondMainTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PartnerVariantType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.PlayerAttackedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MichelangeloTheHeart extends CardImpl { + + public MichelangeloTheHeart(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Raid (the Fridge) -- At the beginning of your second main phase, if you attacked this turn, put a +1/+1 counter on target creature and create a Food token. + Ability ability = new BeginningOfSecondMainTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ).withInterveningIf(RaidCondition.instance); + ability.addEffect(new CreateTokenEffect(new FoodToken()).concatBy("and")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability.addHint(RaidHint.instance).withFlavorWord("Raid (the Fridge)"), new PlayerAttackedWatcher()); + + // Partner--Character select + this.addAbility(PartnerVariantType.CHARACTER_SELECT.makeAbility()); + } + + private MichelangeloTheHeart(final MichelangeloTheHeart card) { + super(card); + } + + @Override + public MichelangeloTheHeart copy() { + return new MichelangeloTheHeart(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java b/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java index 5bd75ba5f7c..1dafc0881e8 100644 --- a/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java +++ b/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java @@ -1,13 +1,14 @@ package mage.cards.m; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; @@ -20,24 +21,26 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MichikosReignOfTruth extends CardImpl { +public final class MichikosReignOfTruth extends TransformingDoubleFacedCard { private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( StaticFilters.FILTER_PERMANENT_CONTROLLED_ARTIFACT_OR_ENCHANTMENT ); public MichikosReignOfTruth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.p.PortraitOfMichiko.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{W}", + "Portrait of Michiko", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE}, "W" + ); + // Michiko's Reign of Truth // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // 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, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn) .setText("target creature gets +1/+1 until end of turn " + "for each artifact and/or enchantment you control"), @@ -45,10 +48,16 @@ public final class MichikosReignOfTruth extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); - this.addAbility(sagaAbility); + // Portrait of Michiko + this.getRightHalfCard().setPT(0, 0); + + // Portrait of Michiko gets +1/+1 for each artifact and/or enchantment you control. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) + .setText("{this} gets +1/+1 for each artifact and/or enchantment you control")) + ); } private MichikosReignOfTruth(final MichikosReignOfTruth card) { diff --git a/Mage.Sets/src/mage/cards/m/MilesMorales.java b/Mage.Sets/src/mage/cards/m/MilesMorales.java index 6069cffefeb..3e0f040fb29 100644 --- a/Mage.Sets/src/mage/cards/m/MilesMorales.java +++ b/Mage.Sets/src/mage/cards/m/MilesMorales.java @@ -60,7 +60,7 @@ public final class MilesMorales extends ModalDoubleFacedCard { // When Miles Morales enters, put a +1/+1 counter on each of up to two target creatures. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); ability.addTarget(new TargetCreaturePermanent(0, 2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {3}{R}{G}{W}: Transform Miles Morales. Activate only as a sorcery. this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/m/MilitiaRallier.java b/Mage.Sets/src/mage/cards/m/MilitiaRallier.java index a8d84fc63d9..169cd036ee7 100644 --- a/Mage.Sets/src/mage/cards/m/MilitiaRallier.java +++ b/Mage.Sets/src/mage/cards/m/MilitiaRallier.java @@ -3,8 +3,9 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.keyword.CantAttackAloneAbility; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -27,7 +28,7 @@ public final class MilitiaRallier extends CardImpl { this.toughness = new MageInt(3); // Militia Rallier can't attack alone. - this.addAbility(new CantAttackAloneAbility()); + this.addAbility(new SimpleStaticAbility(new CantAttackAloneSourceEffect())); // Whenever Militia Rallier attacks, untap target creature. Ability ability = new AttacksTriggeredAbility(new UntapTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/m/MinasTirith.java b/Mage.Sets/src/mage/cards/m/MinasTirith.java index 6e580899c59..a284fc8d02e 100644 --- a/Mage.Sets/src/mage/cards/m/MinasTirith.java +++ b/Mage.Sets/src/mage/cards/m/MinasTirith.java @@ -4,7 +4,7 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.common.YouControlPermanentCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -16,8 +16,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; import mage.constants.WatcherScope; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.util.CardUtil; @@ -32,21 +30,14 @@ import java.util.UUID; */ public final class MinasTirith extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter); - public MinasTirith(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); // Minas Tirith enters the battlefield tapped unless you control a legendary creature. - this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint())); + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); // {T}: Add {W}. this.addAbility(new WhiteManaAbility()); diff --git a/Mage.Sets/src/mage/cards/m/MinesOfMoria.java b/Mage.Sets/src/mage/cards/m/MinesOfMoria.java index 6738cdaceda..b940d83cd11 100644 --- a/Mage.Sets/src/mage/cards/m/MinesOfMoria.java +++ b/Mage.Sets/src/mage/cards/m/MinesOfMoria.java @@ -3,7 +3,7 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.YouControlPermanentCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,8 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.TreasureToken; import mage.target.common.TargetCardInYourGraveyard; @@ -25,21 +23,14 @@ import java.util.UUID; */ public final class MinesOfMoria extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter); - public MinesOfMoria(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); // Mines of Moria enters the battlefield tapped unless you control a legendary creature. - this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint())); + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); // {T}: Add {R}. this.addAbility(new RedManaAbility()); diff --git a/Mage.Sets/src/mage/cards/m/MirrorRoomFracturedRealm.java b/Mage.Sets/src/mage/cards/m/MirrorRoomFracturedRealm.java new file mode 100644 index 00000000000..16582a29c0a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MirrorRoomFracturedRealm.java @@ -0,0 +1,89 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +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.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MirrorRoomFracturedRealm extends RoomCard { + + public MirrorRoomFracturedRealm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{U}", "{5}{U}{U}"); + + // Mirror Room + // When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types. + Ability ability = new UnlockThisDoorTriggeredAbility( + new CreateTokenCopyTargetEffect() + .withAdditionalSubType(SubType.REFLECTION) + .setText("create a token that's a copy of target creature you control, " + + "except it's a Reflection in addition to its other creature types"), + false, true + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.getLeftHalfCard().addAbility(ability); + + // Fractured Realm + // If a triggered ability of a permanent you control triggers, that ability triggers an additional time. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new FracturedRealmEffect())); + } + + private MirrorRoomFracturedRealm(final MirrorRoomFracturedRealm card) { + super(card); + } + + @Override + public MirrorRoomFracturedRealm copy() { + return new MirrorRoomFracturedRealm(this); + } +} + +class FracturedRealmEffect extends ReplacementEffectImpl { + + FracturedRealmEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "if a triggered ability of a permanent you control triggers, " + + "that ability triggers an additional time"; + } + + private FracturedRealmEffect(final FracturedRealmEffect effect) { + super(effect); + } + + @Override + public FracturedRealmEffect copy() { + return new FracturedRealmEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.NUMBER_OF_TRIGGERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + return permanent != null && permanent.isControlledBy(source.getControllerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.overflowInc(event.getAmount(), 1)); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java b/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java index b067aeded81..16b91dec7da 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java +++ b/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java @@ -1,18 +1,26 @@ package mage.cards.m; -import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CopyPermanentEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; import mage.util.functions.CopyApplier; import java.util.UUID; @@ -20,24 +28,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MirrorhallMimic extends CardImpl { +public final class MirrorhallMimic extends TransformingDoubleFacedCard { public MirrorhallMimic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{3}{U}", + "Ghastly Mimicry", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U" + ); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.secondSideCardClazz = mage.cards.g.GhastlyMimicry.class; + // Mirrorhall Mimic + this.getLeftHalfCard().setPT(0, 0); // 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( + this.getLeftHalfCard().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 as a copy of any creature on the battlefield, except it's a Spirit in addition to its other types.", null)); + + + // Ghastly Mimicry + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); // Disturb {3}{U}{U} - this.addAbility(new DisturbAbility(this, "{3}{U}{U}")); + // needs to be added after enchant ability is set for target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{U}{U}")); + + // At the beginning of your upkeep, create a token that's a copy of enchanted creature, except it's a Spirit in addition to its other types. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new GhastlyMimicryEffect())); + + // If Ghastly Mimicry would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private MirrorhallMimic(final MirrorhallMimic card) { @@ -58,3 +82,36 @@ class MirrorhallMimicApplier extends CopyApplier { return true; } } + +class GhastlyMimicryEffect extends OneShotEffect { + + GhastlyMimicryEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of enchanted creature, " + + "except it's a Spirit in addition to its other types"; + } + + private GhastlyMimicryEffect(final GhastlyMimicryEffect effect) { + super(effect); + } + + @Override + public GhastlyMimicryEffect copy() { + return new GhastlyMimicryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent == null) { + return false; + } + Permanent attached = game.getPermanent(permanent.getAttachedTo()); + if (attached == null) { + return false; + } + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.withAdditionalSubType(SubType.SPIRIT); + return effect.setTargetPointer(new FixedTarget(attached, game)).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java b/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java index 2f3a7ac6a8f..6071a0a11a1 100644 --- a/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java +++ b/Mage.Sets/src/mage/cards/m/MischievousCatgeist.java @@ -1,38 +1,64 @@ package mage.cards.m; -import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +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 TheElk801 */ -public final class MischievousCatgeist extends CardImpl { +public final class MischievousCatgeist extends TransformingDoubleFacedCard { public MischievousCatgeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.CAT, SubType.SPIRIT}, "{1}{U}", + "Catlike Curiosity", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U" + ); - this.subtype.add(SubType.CAT); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.c.CatlikeCuriosity.class; + // Mischievous Catgeist + this.getLeftHalfCard().setPT(1, 1); // Whenever Mischievous Catgeist deals combat damage to a player, draw card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new DrawCardSourceControllerEffect(1), false )); + + // Catlike Curiosity + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + // Disturb {2}{U} - this.addAbility(new DisturbAbility(this, "{2}{U}")); + // needs to be added after enchant ability is set for target + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{U}")); + + // Enchanted creature has "Whenever this creature deals combat damage to a player, draw a card." + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ).setTriggerPhrase("Whenever this creature deals combat damage to a player, "), AttachmentType.AURA + ))); + + // If Catlike Curiosity would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private MischievousCatgeist(final MischievousCatgeist card) { diff --git a/Mage.Sets/src/mage/cards/m/MisterFantastic.java b/Mage.Sets/src/mage/cards/m/MisterFantastic.java new file mode 100644 index 00000000000..60178f8b45a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MisterFantastic.java @@ -0,0 +1,67 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CopyTargetStackObjectEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +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.TargetStackObject; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MisterFantastic extends CardImpl { + + public MisterFantastic(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCIENTIST); + this.subtype.add(SubType.HERO); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // At the beginning of combat on your turn, if you've cast a noncreature spell this turn, draw a card. + this.addAbility(new BeginningOfCombatTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .withInterveningIf(CastNoncreatureSpellThisTurnCondition.instance) + .addHint(CastNoncreatureSpellThisTurnCondition.getHint())); + + // {R}{G}{W}{U}, {T}: Copy target triggered ability you control twice. You may choose new targets for the copies. + Ability ability = new SimpleActivatedAbility(new CopyTargetStackObjectEffect() + .setText("copy target triggered ability you control twice"), new ManaCostsImpl<>("{R}{G}{W}{U}")); + ability.addCost(new TapSourceCost()); + ability.addEffect(new CopyTargetStackObjectEffect().setText("You may choose new targets for the copies.")); + ability.addTarget(new TargetStackObject(StaticFilters.FILTER_CONTROLLED_TRIGGERED_ABILITY)); + this.addAbility(ability); + } + + private MisterFantastic(final MisterFantastic card) { + super(card); + } + + @Override + public MisterFantastic copy() { + return new MisterFantastic(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MisterNegative.java b/Mage.Sets/src/mage/cards/m/MisterNegative.java index 47f035eccda..01f556e6c58 100644 --- a/Mage.Sets/src/mage/cards/m/MisterNegative.java +++ b/Mage.Sets/src/mage/cards/m/MisterNegative.java @@ -59,7 +59,7 @@ class MisterNegativeEffect extends OneShotEffect { MisterNegativeEffect() { super(Outcome.Neutral); - staticText = "When {this} enters, you may exchange your life total with target opponent. If you lose life this way, draw that many cards."; + staticText = "you may exchange life totals with target opponent. If you lose life this way, draw that many cards."; } protected MisterNegativeEffect(final MisterNegativeEffect effect) { @@ -82,6 +82,7 @@ class MisterNegativeEffect extends OneShotEffect { controller.exchangeLife(player, source, game); int lifeChange = startingLife - controller.getLife(); if (lifeChange > 0) { + game.processAction(); controller.drawCards(lifeChange, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MistyPalmsOasis.java b/Mage.Sets/src/mage/cards/m/MistyPalmsOasis.java new file mode 100644 index 00000000000..50422cf804a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MistyPalmsOasis.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +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.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +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 MistyPalmsOasis extends CardImpl { + + public MistyPalmsOasis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W} or {B}. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlackManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private MistyPalmsOasis(final MistyPalmsOasis card) { + super(card); + } + + @Override + public MistyPalmsOasis copy() { + return new MistyPalmsOasis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoggFlunkies.java b/Mage.Sets/src/mage/cards/m/MoggFlunkies.java index 39d4f7849c3..04d543b74f6 100644 --- a/Mage.Sets/src/mage/cards/m/MoggFlunkies.java +++ b/Mage.Sets/src/mage/cards/m/MoggFlunkies.java @@ -1,30 +1,29 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author magenoxx_at_gmail.com */ public final class MoggFlunkies extends CardImpl { public MoggFlunkies(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.GOBLIN); this.power = new MageInt(3); this.toughness = new MageInt(3); // Mogg Flunkies can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private MoggFlunkies(final MoggFlunkies card) { diff --git a/Mage.Sets/src/mage/cards/m/MokuMeanderingDrummer.java b/Mage.Sets/src/mage/cards/m/MokuMeanderingDrummer.java new file mode 100644 index 00000000000..df3a746648d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MokuMeanderingDrummer.java @@ -0,0 +1,53 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +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.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MokuMeanderingDrummer extends CardImpl { + + public MokuMeanderingDrummer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a noncreature spell, you may pay {1}. If you do, Moku gets +2/+1 and creatures you control gain haste until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid( + new BoostSourceEffect(2, 1, Duration.EndOfTurn) + .setText("{this} gets +2/+1"), new GenericManaCost(1) + ).addEffect(new GainAbilityAllEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ).concatBy("and")), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false)); + } + + private MokuMeanderingDrummer(final MokuMeanderingDrummer card) { + super(card); + } + + @Override + public MokuMeanderingDrummer copy() { + return new MokuMeanderingDrummer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MolderingGymWeightRoom.java b/Mage.Sets/src/mage/cards/m/MolderingGymWeightRoom.java new file mode 100644 index 00000000000..298ffeede31 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MolderingGymWeightRoom.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MolderingGymWeightRoom extends RoomCard { + + public MolderingGymWeightRoom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{G}", "{5}{G}"); + + // Moldering Gym + // When you unlock this door, search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility( + new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ), false, true + )); + + // Weight Room + // When you unlock this door, manifest dread, then put three +1/+1 counters on that creature. + this.getRightHalfCard().addAbility(new UnlockThisDoorTriggeredAbility( + new ManifestDreadEffect(CounterType.P1P1.createInstance(3)), false, false + )); + } + + private MolderingGymWeightRoom(final MolderingGymWeightRoom card) { + super(card); + } + + @Override + public MolderingGymWeightRoom copy() { + return new MolderingGymWeightRoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MomoPlayfulPet.java b/Mage.Sets/src/mage/cards/m/MomoPlayfulPet.java new file mode 100644 index 00000000000..48eede2e37e --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MomoPlayfulPet.java @@ -0,0 +1,65 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +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.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MomoPlayfulPet extends CardImpl { + + public MomoPlayfulPet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.LEMUR); + this.subtype.add(SubType.BAT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Momo leaves the battlefield, choose one -- + // * Create a Food token. + Ability ability = new LeavesBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken())); + + // * Put a +1/+1 counter on target creature you control. + ability.addMode(new Mode(new AddCountersTargetEffect(CounterType.P1P1.createInstance())) + .addTarget(new TargetControlledCreaturePermanent())); + + // * Scry 2. + ability.addMode(new Mode(new ScryEffect(2))); + this.addAbility(ability); + } + + private MomoPlayfulPet(final MomoPlayfulPet card) { + super(card); + } + + @Override + public MomoPlayfulPet copy() { + return new MomoPlayfulPet(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MomosHeist.java b/Mage.Sets/src/mage/cards/m/MomosHeist.java new file mode 100644 index 00000000000..aeef02004db --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MomosHeist.java @@ -0,0 +1,46 @@ +package mage.cards.m; + +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +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.target.common.TargetArtifactPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MomosHeist extends CardImpl { + + public MomosHeist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Gain control of target artifact. Untap it. It gains haste. At the beginning of the next end step, sacrifice it. + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom)); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it")); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.Custom + ).setText("It gains haste")); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeTargetEffect("sacrifice it")), true + )); + } + + private MomosHeist(final MomosHeist card) { + super(card); + } + + @Override + public MomosHeist copy() { + return new MomosHeist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MondronenShaman.java b/Mage.Sets/src/mage/cards/m/MondronenShaman.java index 8683524fe7d..dca147c4d8d 100644 --- a/Mage.Sets/src/mage/cards/m/MondronenShaman.java +++ b/Mage.Sets/src/mage/cards/m/MondronenShaman.java @@ -1,34 +1,48 @@ package mage.cards.m; -import mage.MageInt; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author North */ -public final class MondronenShaman extends CardImpl { +public final class MondronenShaman extends TransformingDoubleFacedCard { public MondronenShaman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{3}{R}", + "Tovolar's Magehunter", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - - this.secondSideCardClazz = mage.cards.t.TovolarsMagehunter.class; + // Mondronen Shaman + this.getLeftHalfCard().setPT(3, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Mondronen Shaman. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Tovolar's Magehunter + this.getRightHalfCard().setPT(5, 5); + + // Whenever an opponent casts a spell, Tovolar's Magehunter deals 2 damage to that player. + this.getRightHalfCard().addAbility(new SpellCastOpponentTriggeredAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player"), + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Tovolar's Magehunter. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private MondronenShaman(final MondronenShaman card) { diff --git a/Mage.Sets/src/mage/cards/m/MonkGyatso.java b/Mage.Sets/src/mage/cards/m/MonkGyatso.java new file mode 100644 index 00000000000..40358b3ad4d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MonkGyatso.java @@ -0,0 +1,44 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.BecomesTargetAnyTriggeredAbility; +import mage.abilities.effects.keyword.AirbendTargetEffect; +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 MonkGyatso extends CardImpl { + + public MonkGyatso(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever another creature you control becomes the target of a spell or ability, you may airbend that creature. + this.addAbility(new BecomesTargetAnyTriggeredAbility( + new AirbendTargetEffect().setText("airbend that creature"), + StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL + ).setOptional(true)); + } + + private MonkGyatso(final MonkGyatso card) { + super(card); + } + + @Override + public MonkGyatso copy() { + return new MonkGyatso(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoonGirlAndDevilDinosaur.java b/Mage.Sets/src/mage/cards/m/MoonGirlAndDevilDinosaur.java new file mode 100644 index 00000000000..43fed2da365 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoonGirlAndDevilDinosaur.java @@ -0,0 +1,60 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MoonGirlAndDevilDinosaur extends CardImpl { + + public MoonGirlAndDevilDinosaur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DINOSAUR); + this.subtype.add(SubType.HERO); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you draw your second card each turn, until end of turn, Moon Girl and Devil Dinosaur's base power and toughness become 6/6 and they gain trample. + Ability ability = new DrawNthCardTriggeredAbility( + new SetBasePowerToughnessSourceEffect(6, 6, Duration.EndOfTurn) + .setText("until end of turn, {this}'s base power and toughness become 6/6") + ); + ability.addEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and they gain trample")); + this.addAbility(ability); + + // Whenever an artifact you control enters, draw a card. This ability triggers only once each turn. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT + ).setTriggersLimitEachTurn(1)); + } + + private MoonGirlAndDevilDinosaur(final MoonGirlAndDevilDinosaur card) { + super(card); + } + + @Override + public MoonGirlAndDevilDinosaur copy() { + return new MoonGirlAndDevilDinosaur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoonlitAmbusher.java b/Mage.Sets/src/mage/cards/m/MoonlitAmbusher.java deleted file mode 100644 index ee33eed54c2..00000000000 --- a/Mage.Sets/src/mage/cards/m/MoonlitAmbusher.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -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 MoonlitAmbusher extends CardImpl { - - public MoonlitAmbusher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(3); - this.color.setGreen(true); - this.nightCard = true; - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private MoonlitAmbusher(final MoonlitAmbusher card) { - super(card); - } - - @Override - public MoonlitAmbusher copy() { - return new MoonlitAmbusher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MoonrageBrute.java b/Mage.Sets/src/mage/cards/m/MoonrageBrute.java deleted file mode 100644 index 1b9ed12ce72..00000000000 --- a/Mage.Sets/src/mage/cards/m/MoonrageBrute.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.WardAbility; -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 MoonrageBrute extends CardImpl { - - public MoonrageBrute(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - - // Ward—Pay 3 life. - this.addAbility(new WardAbility(new PayLifeCost(3), false)); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private MoonrageBrute(final MoonrageBrute card) { - super(card); - } - - @Override - public MoonrageBrute copy() { - return new MoonrageBrute(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MoonriseIntruder.java b/Mage.Sets/src/mage/cards/m/MoonriseIntruder.java deleted file mode 100644 index 0d53062f18e..00000000000 --- a/Mage.Sets/src/mage/cards/m/MoonriseIntruder.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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 fireshoes - */ -public final class MoonriseIntruder extends CardImpl { - - public MoonriseIntruder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Moonrise Intruder. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private MoonriseIntruder(final MoonriseIntruder card) { - super(card); - } - - @Override - public MoonriseIntruder copy() { - return new MoonriseIntruder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MoonscarredWerewolf.java b/Mage.Sets/src/mage/cards/m/MoonscarredWerewolf.java deleted file mode 100644 index 7bc6a02be36..00000000000 --- a/Mage.Sets/src/mage/cards/m/MoonscarredWerewolf.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.keyword.VigilanceAbility; -import mage.abilities.mana.SimpleManaAbility; -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 North - */ -public final class MoonscarredWerewolf extends CardImpl { - - public MoonscarredWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - this.color.setGreen(true); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.addAbility(VigilanceAbility.getInstance()); - - // {tap}: Add {G}{G}. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new TapSourceCost())); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Moonscarred Werewolf. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private MoonscarredWerewolf(final MoonscarredWerewolf card) { - super(card); - } - - @Override - public MoonscarredWerewolf copy() { - return new MoonscarredWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java b/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java index addd453c276..1eae1d6cade 100644 --- a/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java +++ b/Mage.Sets/src/mage/cards/m/MoraugFuryOfAkoum.java @@ -40,7 +40,7 @@ public final class MoraugFuryOfAkoum extends CardImpl { this.addAbility(new SimpleStaticAbility(new MoraugFuryOfAkoumBoostEffect())); // Landfall — Whenever a land you control enters, if it's your main phase, there's an additional combat phase after this phase. At the beginning of that combat, untap all creatures you control. - this.addAbility(new LandfallAbility(new MoraugFuryOfAkoumCombatEffect()).withInterveningIf(IsMainPhaseCondition.YOUR), new MoraugFuryOfAkoumWatcher()); + this.addAbility(new LandfallAbility(new MoraugFuryOfAkoumCombatEffect()).withInterveningIf(IsMainPhaseCondition.YOURS), new MoraugFuryOfAkoumWatcher()); } private MoraugFuryOfAkoum(final MoraugFuryOfAkoum card) { diff --git a/Mage.Sets/src/mage/cards/m/MorningApparition.java b/Mage.Sets/src/mage/cards/m/MorningApparition.java deleted file mode 100644 index 22db5e1d308..00000000000 --- a/Mage.Sets/src/mage/cards/m/MorningApparition.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -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.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class MorningApparition extends CardImpl { - - public MorningApparition(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // If Morning Apparition would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private MorningApparition(final MorningApparition card) { - super(card); - } - - @Override - public MorningApparition copy() { - return new MorningApparition(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MourningPatrol.java b/Mage.Sets/src/mage/cards/m/MourningPatrol.java index d04ce198bd0..0dc7e48038b 100644 --- a/Mage.Sets/src/mage/cards/m/MourningPatrol.java +++ b/Mage.Sets/src/mage/cards/m/MourningPatrol.java @@ -1,11 +1,10 @@ package mage.cards.m; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DisturbAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,22 +13,35 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MourningPatrol extends CardImpl { +public final class MourningPatrol extends TransformingDoubleFacedCard { public MourningPatrol(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{2}{W}", + "Morning Apparition", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "W" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.m.MorningApparition.class; + // Mourning Patrol + this.getLeftHalfCard().setPT(2, 3); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Disturb {3}{W} - this.addAbility(new DisturbAbility(this, "{3}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{W}")); + + // Morning Apparition + this.getRightHalfCard().setPT(2, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // If Morning Apparition would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private MourningPatrol(final MourningPatrol card) { diff --git a/Mage.Sets/src/mage/cards/m/Mournwillow.java b/Mage.Sets/src/mage/cards/m/Mournwillow.java index e6bdde9bae8..bc5c5b3630e 100644 --- a/Mage.Sets/src/mage/cards/m/Mournwillow.java +++ b/Mage.Sets/src/mage/cards/m/Mournwillow.java @@ -1,20 +1,16 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; -import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantBlockAllEffect; import mage.abilities.keyword.HasteAbility; 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.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; @@ -23,6 +19,11 @@ import java.util.UUID; */ public final class Mournwillow extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 2 or less"); + static { + filter.add(new PowerPredicate(ComparisonType.OR_LESS, 2)); + } + public Mournwillow(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); this.subtype.add(SubType.PLANT); @@ -35,7 +36,7 @@ public final class Mournwillow extends CardImpl { // Delirium — When Mournwillow enters the battlefield, if there are four or more card types among cards in your graveyard, // creatures with power 2 or less can't block this turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MournwillowEffect()) + this.addAbility(new EntersBattlefieldTriggeredAbility(new CantBlockAllEffect(filter, Duration.EndOfTurn)) .withInterveningIf(DeliriumCondition.instance) .setAbilityWord(AbilityWord.DELIRIUM) .addHint(CardTypesInGraveyardCount.YOU.getHint())); @@ -50,30 +51,3 @@ public final class Mournwillow extends CardImpl { return new Mournwillow(this); } } - -class MournwillowEffect extends RestrictionEffect { - - MournwillowEffect() { - super(Duration.EndOfTurn); - staticText = "creatures with power 2 or less can't block this turn"; - } - - private MournwillowEffect(final MournwillowEffect effect) { - super(effect); - } - - @Override - public MournwillowEffect copy() { - return new MournwillowEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getPower().getValue() <= 2; - } - - @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java b/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java index a1f961a9e97..c869ac7503e 100644 --- a/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java +++ b/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java @@ -38,7 +38,7 @@ public final class MuYanlingCelestialWind extends CardImpl { Ability ability = new LoyaltyAbility(new BoostTargetEffect( -5, 0, Duration.UntilYourNextTurn ).setText("Until your next turn, up to one target creature gets -5/-0."), 1); - ability.addTarget(new TargetCreaturePermanent()); + ability.addTarget(new TargetCreaturePermanent(0, 1)); this.addAbility(ability); // −3: Return up to two target creatures to their owners' hands. diff --git a/Mage.Sets/src/mage/cards/m/MycoidMaze.java b/Mage.Sets/src/mage/cards/m/MycoidMaze.java deleted file mode 100644 index 04fa111f543..00000000000 --- a/Mage.Sets/src/mage/cards/m/MycoidMaze.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.m; - -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.LookLibraryAndPickControllerEffect; -import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author xenohedron - */ -public final class MycoidMaze extends CardImpl { - - public MycoidMaze(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.subtype.add(SubType.CAVE); - - // (Transforms from Twists and Turns.) - this.nightCard = true; - - // {T}: Add {G}. - this.addAbility(new GreenManaAbility()); - - // {3}{G}, {T}: Look at the top four cards of your library. You may reveal a creature card from among them and put that card 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<>("{3}{G}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - - } - - private MycoidMaze(final MycoidMaze card) { - super(card); - } - - @Override - public MycoidMaze copy() { - return new MycoidMaze(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MycosynthLattice.java b/Mage.Sets/src/mage/cards/m/MycosynthLattice.java index cbefd32b853..7f14adf8639 100644 --- a/Mage.Sets/src/mage/cards/m/MycosynthLattice.java +++ b/Mage.Sets/src/mage/cards/m/MycosynthLattice.java @@ -134,10 +134,10 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { affectedCards.forEach(card -> { game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless); - // mdf cards - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + // df cards + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless); game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless); } @@ -151,6 +151,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl { } // double faces cards + // TODO: can remove after tdfc rework if (card.getSecondCardFace() != null) { game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless); } diff --git a/Mage.Sets/src/mage/cards/m/MysteriousTome.java b/Mage.Sets/src/mage/cards/m/MysteriousTome.java index 100d607c828..2ec392d7ace 100644 --- a/Mage.Sets/src/mage/cards/m/MysteriousTome.java +++ b/Mage.Sets/src/mage/cards/m/MysteriousTome.java @@ -5,32 +5,42 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetNonlandPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class MysteriousTome extends CardImpl { +public final class MysteriousTome extends TransformingDoubleFacedCard { public MysteriousTome(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); - - this.secondSideCardClazz = mage.cards.c.ChillingChronicle.class; - - // {2}, {T}: Draw a card. Transform Mysterious Tome. - this.addAbility(new TransformAbility()); - Ability ability = new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(1), new GenericManaCost(2) + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{U}", + "Chilling Chronicle", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U" ); + + // Mysterious Tome + // {2}, {T}: Draw a card. Transform Mysterious Tome. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addEffect(new TransformSourceEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Chilling Chronicle + // {1}, {T}: Tap target nonland permanent. Transform Chilling Chronicle. + Ability backAbility = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); + backAbility.addCost(new TapSourceCost()); + backAbility.addEffect(new TransformSourceEffect()); + backAbility.addTarget(new TargetNonlandPermanent()); + this.getRightHalfCard().addAbility(backAbility); } private MysteriousTome(final MysteriousTome card) { diff --git a/Mage.Sets/src/mage/cards/m/MysticMonstrosity.java b/Mage.Sets/src/mage/cards/m/MysticMonstrosity.java deleted file mode 100644 index 3ba9014ef37..00000000000 --- a/Mage.Sets/src/mage/cards/m/MysticMonstrosity.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.m; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.mana.AnyColorManaAbility; -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 MysticMonstrosity extends CardImpl { - - public MysticMonstrosity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(5); - this.toughness = new MageInt(6); - this.nightCard = true; - - // Lands you control have "{T}: Add one mana of any color." - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new AnyColorManaAbility(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_LANDS, false - ))); - } - - private MysticMonstrosity(final MysticMonstrosity card) { - super(card); - } - - @Override - public MysticMonstrosity copy() { - return new MysticMonstrosity(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MysticSkull.java b/Mage.Sets/src/mage/cards/m/MysticSkull.java index e9a14a86354..8554136f024 100644 --- a/Mage.Sets/src/mage/cards/m/MysticSkull.java +++ b/Mage.Sets/src/mage/cards/m/MysticSkull.java @@ -2,37 +2,51 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 MysticSkull extends CardImpl { +public final class MysticSkull extends TransformingDoubleFacedCard { public MysticSkull(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.secondSideCardClazz = mage.cards.m.MysticMonstrosity.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "Mystic Monstrosity", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.CONSTRUCT}, "" + ); + // Mystic Skull // {1}, {T}: Add one mana of any color. Ability ability = new AnyColorManaAbility(new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {5}, {T}: Transform Mystic Skull. - this.addAbility(new TransformAbility()); ability = new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Mystic Monstrosity + this.getRightHalfCard().setPT(5, 6); + + // Lands you control have "{T}: Add one mana of any color." + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new AnyColorManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS, false + ))); } private MysticSkull(final MysticSkull card) { diff --git a/Mage.Sets/src/mage/cards/n/NamelessConqueror.java b/Mage.Sets/src/mage/cards/n/NamelessConqueror.java deleted file mode 100644 index 2151a7b5730..00000000000 --- a/Mage.Sets/src/mage/cards/n/NamelessConqueror.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -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.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class NamelessConqueror extends CardImpl { - - public NamelessConqueror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SAMURAI); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - } - - private NamelessConqueror(final NamelessConqueror card) { - super(card); - } - - @Override - public NamelessConqueror copy() { - return new NamelessConqueror(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NamorTheSubMariner.java b/Mage.Sets/src/mage/cards/n/NamorTheSubMariner.java new file mode 100644 index 00000000000..f1dfef46e5a --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NamorTheSubMariner.java @@ -0,0 +1,116 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; +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.*; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.token.MerfolkToken; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NamorTheSubMariner extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.MERFOLK)); + private static final Hint hint = new ValueHint("Merfolk you control", xValue); + private static final FilterSpell filter = new FilterSpell("a noncreature spell with one or more blue mana symbols in its mana cost"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(NamorTheSubMarinerPredicate.instance); + } + + public NamorTheSubMariner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Namor's power is equal to the number of Merfolk you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerSourceEffect(xValue))); + + // Whenever you cast a noncreature spell with one or more blue mana symbols in its mana cost, create that many 1/1 blue Merfolk creature tokens. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new MerfolkToken(), NamorTheSubMarinerValue.instance), filter, false + )); + } + + private NamorTheSubMariner(final NamorTheSubMariner card) { + super(card); + } + + @Override + public NamorTheSubMariner copy() { + return new NamorTheSubMariner(this); + } +} + +enum NamorTheSubMarinerPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return input + .getManaCost() + .stream() + .anyMatch(manaCost -> manaCost.containsColor(ColoredManaSymbol.U)); + } +} + +enum NamorTheSubMarinerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Spell spell = (Spell) effect.getValue("spellCast"); + return spell != null + ? spell + .getManaCost() + .stream() + .mapToInt(manaCost -> manaCost.containsColor(ColoredManaSymbol.U) ? 1 : 0) + .sum() + : 0; + } + + @Override + public NamorTheSubMarinerValue copy() { + return this; + } + + @Override + public String getMessage() { + return "that many"; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NathanDrakeTreasureHunter.java b/Mage.Sets/src/mage/cards/n/NathanDrakeTreasureHunter.java new file mode 100644 index 00000000000..357256402c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NathanDrakeTreasureHunter.java @@ -0,0 +1,140 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class NathanDrakeTreasureHunter extends CardImpl { + + public NathanDrakeTreasureHunter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // You may spend mana as though it were mana of any color to cast spells you don't own or to activate abilities of permanents you control but don't own. + this.addAbility(new SimpleStaticAbility(new NathanDrakeTreasureHunterManaEffect())); + + // Whenever Nathan Drake attacks, exile the top card of each player's library. You may cast a spell from among those cards. + this.addAbility(new AttacksTriggeredAbility(new NathanDrakeTreasureHunterCastEffect())); + } + + private NathanDrakeTreasureHunter(final NathanDrakeTreasureHunter card) { + super(card); + } + + @Override + public NathanDrakeTreasureHunter copy() { + return new NathanDrakeTreasureHunter(this); + } +} + +class NathanDrakeTreasureHunterManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + NathanDrakeTreasureHunterManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); + staticText = "you may spend mana as though it were mana of any color to cast spells you don't own " + + "or to activate abilities of permanents you control but don't own"; + } + + private NathanDrakeTreasureHunterManaEffect(final NathanDrakeTreasureHunterManaEffect effect) { + super(effect); + } + + @Override + public NathanDrakeTreasureHunterManaEffect copy() { + return new NathanDrakeTreasureHunterManaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Card card = game.getCard(CardUtil.getMainCardId(game, objectId)); + return card != null && !card.isOwnedBy(affectedControllerId); + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} + +class NathanDrakeTreasureHunterCastEffect extends OneShotEffect { + + NathanDrakeTreasureHunterCastEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of each player's library. You may cast a spell from among those cards"; + } + + private NathanDrakeTreasureHunterCastEffect(final NathanDrakeTreasureHunterCastEffect effect) { + super(effect); + } + + @Override + public NathanDrakeTreasureHunterCastEffect copy() { + return new NathanDrakeTreasureHunterCastEffect(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 + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getLibrary) + .map(library -> library.getFromTop(game)) + .collect(Collectors.toSet())); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + cards.removeIf(uuid -> CardUtil.getCastableComponents( + game.getCard(uuid), StaticFilters.FILTER_CARD, + source, player, game, null, false + ).isEmpty()); + TargetCard target = new TargetCardInExile(0, 1, StaticFilters.FILTER_CARD); + target.withChooseHint("to cast"); + target.withNotTarget(true); + player.choose(Outcome.DrawCard, cards, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + CardUtil.castSingle(player, source, game, card); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NeckBreaker.java b/Mage.Sets/src/mage/cards/n/NeckBreaker.java deleted file mode 100644 index 96ced371e3f..00000000000 --- a/Mage.Sets/src/mage/cards/n/NeckBreaker.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -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.StaticFilters; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class NeckBreaker extends CardImpl { - - public NeckBreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Attacking creatures you control get +1/+0 and have trample. - Ability ability = new SimpleStaticAbility(new BoostControlledEffect( - 1, 0, Duration.WhileOnBattlefield, - StaticFilters.FILTER_ATTACKING_CREATURES - )); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_ATTACKING_CREATURES - ).setText("and have trample")); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Neck Breaker. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private NeckBreaker(final NeckBreaker card) { - super(card); - } - - @Override - public NeckBreaker copy() { - return new NeckBreaker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java b/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java index 9fa4c5d6e11..12f0e7564f6 100644 --- a/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java +++ b/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java @@ -1,13 +1,16 @@ package mage.cards.n; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -21,23 +24,35 @@ import java.util.UUID; /** * @author halljared */ -public final class NeglectedHeirloom extends CardImpl { +public final class NeglectedHeirloom extends TransformingDoubleFacedCard { public NeglectedHeirloom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); - this.subtype.add(SubType.EQUIPMENT); - - this.secondSideCardClazz = mage.cards.a.AshmouthBlade.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "{1}", + "Ashmouth Blade", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "" + ); // Equipped creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); // When equipped creature transforms, transform Neglected Heirloom. - this.addAbility(new TransformAbility()); - this.addAbility(new NeglectedHeirloomTriggeredAbility()); + this.getLeftHalfCard().addAbility(new NeglectedHeirloomTriggeredAbility()); // Equip {1} - this.addAbility(new EquipAbility(1, false)); + this.getLeftHalfCard().addAbility(new EquipAbility(1, false)); + + // Ashmouth Blade + + // Equipped creature gets +3/+3 and has first strike. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3)); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has first strike")); + this.getRightHalfCard().addAbility(ability); + + // Equip {3} + this.getRightHalfCard().addAbility(new EquipAbility(3, false)); } private NeglectedHeirloom(final NeglectedHeirloom card) { diff --git a/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java b/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java index 43c1a721efd..e565a69b724 100644 --- a/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java +++ b/Mage.Sets/src/mage/cards/n/NekusarTheMindrazer.java @@ -33,7 +33,7 @@ public final class NekusarTheMindrazer extends CardImpl { false)); // Whenever an opponent draws a card, Nekusar, the Mindrazer deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private NekusarTheMindrazer(final NekusarTheMindrazer card) { diff --git a/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java b/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java deleted file mode 100644 index d2602d2d66b..00000000000 --- a/Mage.Sets/src/mage/cards/n/NeoExdeathDimensionsEnd.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; -import mage.abilities.keyword.TrampleAbility; -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 NeoExdeathDimensionsEnd extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENTS); - - public NeoExdeathDimensionsEnd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(0); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setBlack(true); - this.color.setGreen(true); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Neo Exdeath's power is equal to the number of permanent cards in your graveyard. - this.addAbility(new SimpleStaticAbility(new SetBasePowerSourceEffect(xValue))); - } - - private NeoExdeathDimensionsEnd(final NeoExdeathDimensionsEnd card) { - super(card); - } - - @Override - public NeoExdeathDimensionsEnd copy() { - return new NeoExdeathDimensionsEnd(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NeonatesRush.java b/Mage.Sets/src/mage/cards/n/NeonatesRush.java index 148c3eeb053..b907fd0b0b3 100644 --- a/Mage.Sets/src/mage/cards/n/NeonatesRush.java +++ b/Mage.Sets/src/mage/cards/n/NeonatesRush.java @@ -1,10 +1,9 @@ package mage.cards.n; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.abilities.hint.ConditionHint; @@ -12,13 +11,9 @@ import mage.abilities.hint.Hint; 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.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -42,7 +37,8 @@ public final class NeonatesRush extends CardImpl { ).addHint(hint).setRuleAtTheTop(true)); // Neonate's Rush deals 1 damage to target creature and 1 damage to its controller. Draw a card. - this.getSpellAbility().addEffect(new NeonatesRushEffect()); + this.getSpellAbility().addEffect(new DamageTargetAndTargetControllerEffect(1, 1) + .setText("{this} deals 1 damage to target creature and 1 damage to its controller")); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -56,34 +52,3 @@ public final class NeonatesRush extends CardImpl { return new NeonatesRush(this); } } - -class NeonatesRushEffect extends OneShotEffect { - - NeonatesRushEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 1 damage to target creature and 1 damage to its controller."; - } - - private NeonatesRushEffect(final NeonatesRushEffect effect) { - super(effect); - } - - @Override - public NeonatesRushEffect copy() { - return new NeonatesRushEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { - return false; - } - permanent.damage(1, source.getSourceId(), source, game); - Player player = game.getPlayer(permanent.getControllerId()); - if (player != null) { - player.damage(1, source.getSourceId(), source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NezumiFreewheeler.java b/Mage.Sets/src/mage/cards/n/NezumiFreewheeler.java index 1c1a0cd081d..3b8b4570297 100644 --- a/Mage.Sets/src/mage/cards/n/NezumiFreewheeler.java +++ b/Mage.Sets/src/mage/cards/n/NezumiFreewheeler.java @@ -1,44 +1,68 @@ package mage.cards.n; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.MillCardsEachPlayerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class NezumiFreewheeler extends CardImpl { +public final class NezumiFreewheeler extends TransformingDoubleFacedCard { + + private static final FilterCard filter + = new FilterPermanentCard("permanent card with mana value 2 or less from a graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } public NezumiFreewheeler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.RAT, SubType.SAMURAI}, "{3}{B}", + "Hideous Fleshwheeler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.RAT}, "WB" + ); - this.subtype.add(SubType.RAT); - this.subtype.add(SubType.SAMURAI); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.h.HideousFleshwheeler.class; + // Nezumi Freewheeler + this.getLeftHalfCard().setPT(3, 3); // Menace - this.addAbility(new MenaceAbility(false)); + this.getLeftHalfCard().addAbility(new MenaceAbility(false)); // When Nezumi Freewheeler enters the battlefield, each player mills three cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsEachPlayerEffect(3, TargetController.EACH_PLAYER))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsEachPlayerEffect(3, TargetController.EACH_PLAYER))); // {5}{W/P}: Transform Nezumi Freewheeler. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{W/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{W/P}"))); + + // Hideous Fleshwheeler + this.getRightHalfCard().setPT(4, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // When this creature transforms into Hideous Fleshwheeler, Hideous Fleshwheeler, put target permanent card with mana value 2 or less from a graveyard onto the battlefield under your control. + Ability ability = new TransformIntoSourceTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); + ability.addTarget(new TargetCardInGraveyard(filter)); + this.getRightHalfCard().addAbility(ability); } private NezumiFreewheeler(final NezumiFreewheeler card) { diff --git a/Mage.Sets/src/mage/cards/n/NezumiRoadCaptain.java b/Mage.Sets/src/mage/cards/n/NezumiRoadCaptain.java deleted file mode 100644 index c3a6420efa2..00000000000 --- a/Mage.Sets/src/mage/cards/n/NezumiRoadCaptain.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -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.filter.FilterPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class NezumiRoadCaptain extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(SubType.VEHICLE, "Vehicles"); - - public NezumiRoadCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.RAT); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Vehicles you control have menace. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new MenaceAbility(true), Duration.WhileOnBattlefield, filter - ))); - } - - private NezumiRoadCaptain(final NezumiRoadCaptain card) { - super(card); - } - - @Override - public NezumiRoadCaptain copy() { - return new NezumiRoadCaptain(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java b/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java deleted file mode 100644 index 48b0c44bf0b..00000000000 --- a/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java +++ /dev/null @@ -1,107 +0,0 @@ -package mage.cards.n; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.constants.SubType; -import mage.constants.SuperType; -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.TargetPlayer; -import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetCreatureOrPlaneswalker; - -/** - * - * @author TheElk801 - */ -public final class NicolBolasTheArisen extends CardImpl { - - private static final FilterCard filter = new FilterCard("creature or planeswalker card from a graveyard"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.PLANESWALKER.getPredicate() - )); - } - - public NicolBolasTheArisen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.BOLAS); - - this.color.setBlue(true); - this.color.setBlack(true); - this.color.setRed(true); - this.nightCard = true; - - this.setStartingLoyalty(7); - - // +2: Draw two cards. - this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 2)); - - // −3: Nicol Bolas, the Arisen deals 10 damage to target creature or planeswalker. - Ability ability = new LoyaltyAbility(new DamageTargetEffect(10), -3); - ability.addTarget(new TargetCreatureOrPlaneswalker()); - this.addAbility(ability); - - // −4: Put target creature or planeswalker card from a graveyard onto the battlefield under your control. - ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), -4); - ability.addTarget(new TargetCardInGraveyard(filter)); - this.addAbility(ability); - - // −12: Exile all but the bottom card of target player's library. - ability = new LoyaltyAbility(new NicolBolasTheArisenEffect(), -12); - ability.addTarget(new TargetPlayer()); - this.addAbility(ability); - } - - private NicolBolasTheArisen(final NicolBolasTheArisen card) { - super(card); - } - - @Override - public NicolBolasTheArisen copy() { - return new NicolBolasTheArisen(this); - } -} - -class NicolBolasTheArisenEffect extends OneShotEffect { - - NicolBolasTheArisenEffect() { - super(Outcome.Benefit); - this.staticText = "Exile all but the bottom card of target player's library."; - } - - private NicolBolasTheArisenEffect(final NicolBolasTheArisenEffect effect) { - super(effect); - } - - @Override - public NicolBolasTheArisenEffect copy() { - return new NicolBolasTheArisenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player controller = game.getPlayer(source.getControllerId()); - if (targetPlayer == null || controller == null) { - return false; - } - return controller.moveCards(targetPlayer.getLibrary().getTopCards(game, targetPlayer.getLibrary().size() - 1), Zone.EXILED, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasTheRavager.java b/Mage.Sets/src/mage/cards/n/NicolBolasTheRavager.java index 9d63d936ede..100a81578e7 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasTheRavager.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasTheRavager.java @@ -1,50 +1,89 @@ package mage.cards.n; -import java.util.UUID; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -import mage.constants.*; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; /** * * @author TheElk801 */ -public final class NicolBolasTheRavager extends CardImpl { +public final class NicolBolasTheRavager extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("creature or planeswalker card from a graveyard"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.PLANESWALKER.getPredicate() + )); + } public NicolBolasTheRavager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.DRAGON}, "{1}{U}{B}{R}", + "Nicol Bolas, the Arisen", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.BOLAS}, "UBR" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.n.NicolBolasTheArisen.class; + // Nicol Bolas, the Ravager + this.getLeftHalfCard().setPT(4, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Nicol Bolas, the Ravager enters the battlefield, each opponent discards a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect(StaticValue.get(1), false, TargetController.OPPONENT))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect(StaticValue.get(1), false, TargetController.OPPONENT))); // {4}{U}{B}{R}: Exile Nicol Bolas, the Ravager, then return him to the battlefield transformed under his owner's control. Activate this ability only any time you could cast a sorcerry. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( Zone.BATTLEFIELD, - new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED,Pronoun.HE), + new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), new ManaCostsImpl<>("{4}{U}{B}{R}") )); + + // Nicol Bolas, the Arisen + this.getRightHalfCard().setStartingLoyalty(7); + + // +2: Draw two cards. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 2)); + + // −3: Nicol Bolas, the Arisen deals 10 damage to target creature or planeswalker. + Ability ability = new LoyaltyAbility(new DamageTargetEffect(10), -3); + ability.addTarget(new TargetCreatureOrPlaneswalker()); + this.getRightHalfCard().addAbility(ability); + + // −4: Put target creature or planeswalker card from a graveyard onto the battlefield under your control. + ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), -4); + ability.addTarget(new TargetCardInGraveyard(filter)); + this.getRightHalfCard().addAbility(ability); + + // −12: Exile all but the bottom card of target player's library. + ability = new LoyaltyAbility(new NicolBolasTheArisenEffect(), -12); + ability.addTarget(new TargetPlayer()); + this.getRightHalfCard().addAbility(ability); } private NicolBolasTheRavager(final NicolBolasTheRavager card) { @@ -56,3 +95,30 @@ public final class NicolBolasTheRavager extends CardImpl { return new NicolBolasTheRavager(this); } } + +class NicolBolasTheArisenEffect extends OneShotEffect { + + NicolBolasTheArisenEffect() { + super(Outcome.Benefit); + this.staticText = "Exile all but the bottom card of target player's library."; + } + + private NicolBolasTheArisenEffect(final NicolBolasTheArisenEffect effect) { + super(effect); + } + + @Override + public NicolBolasTheArisenEffect copy() { + return new NicolBolasTheArisenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (targetPlayer == null || controller == null) { + return false; + } + return controller.moveCards(targetPlayer.getLibrary().getTopCards(game, targetPlayer.getLibrary().size() - 1), Zone.EXILED, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NightfallPredator.java b/Mage.Sets/src/mage/cards/n/NightfallPredator.java deleted file mode 100644 index 275b43fe3cb..00000000000 --- a/Mage.Sets/src/mage/cards/n/NightfallPredator.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.n; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.FightTargetSourceEffect; -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 North - */ -public final class NightfallPredator extends CardImpl { - - public NightfallPredator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - this.color.setGreen(true); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {R}, {tap}: Nightfall Predator fights target creature. - Ability activatedAbility = new SimpleActivatedAbility( - new FightTargetSourceEffect().setText( - "{this} fights target creature. " + - "(Each deals damage equal to its power to the other.)"), - new ManaCostsImpl<>("{R}") - ); - activatedAbility.addCost(new TapSourceCost()); - activatedAbility.addTarget(new TargetCreaturePermanent()); - this.addAbility(activatedAbility); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Nightfall Predator. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private NightfallPredator(final NightfallPredator card) { - super(card); - } - - @Override - public NightfallPredator copy() { - return new NightfallPredator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/n/NightmaresAndDaydreams.java b/Mage.Sets/src/mage/cards/n/NightmaresAndDaydreams.java new file mode 100644 index 00000000000..b314cfa05d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightmaresAndDaydreams.java @@ -0,0 +1,115 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.TargetPlayer; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NightmaresAndDaydreams extends CardImpl { + + public NightmaresAndDaydreams(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_IV); + + // I, II, III -- Until your next turn, whenever you cast an instant or sorcery spell, target player mills cards equal to that spell's mana value. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, + new CreateDelayedTriggeredAbilityEffect(new NightmaresAndDaydreamsTriggeredAbility()) + ); + + // IV -- Draw a card. If a graveyard has twenty or more cards in it, draw three cards instead. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_IV, + new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(3), new DrawCardSourceControllerEffect(1), + NightmaresAndDaydreamsCondition.instance, "draw a card. " + + "If a graveyard has twenty or more cards in it, draw three cards instead" + ) + ); + this.addAbility(sagaAbility); + } + + private NightmaresAndDaydreams(final NightmaresAndDaydreams card) { + super(card); + } + + @Override + public NightmaresAndDaydreams copy() { + return new NightmaresAndDaydreams(this); + } +} + +enum NightmaresAndDaydreamsCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .anyMatch(player -> player.getGraveyard().size() >= 20); + } +} + +class NightmaresAndDaydreamsTriggeredAbility extends DelayedTriggeredAbility { + + NightmaresAndDaydreamsTriggeredAbility() { + super(new MillCardsTargetEffect(SavedDamageValue.MANY) + .setText("target player mills cards equal to that spell's mana value"), + Duration.UntilYourNextTurn, false, false); + this.setTriggerPhrase("Until your next turn, whenever you cast an instant or sorcery spell, "); + this.addTarget(new TargetPlayer()); + } + + private NightmaresAndDaydreamsTriggeredAbility(final NightmaresAndDaydreamsTriggeredAbility ability) { + super(ability); + } + + @Override + public NightmaresAndDaydreamsTriggeredAbility copy() { + return new NightmaresAndDaydreamsTriggeredAbility(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.getSpell(event.getTargetId()); + if (spell == null || !spell.isControlledBy(getControllerId()) || !spell.isInstantOrSorcery(game)) { + return false; + } + this.getEffects().setValue("damage", spell.getManaValue()); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NineLives.java b/Mage.Sets/src/mage/cards/n/NineLives.java index 01257dac79c..9a8a37106be 100644 --- a/Mage.Sets/src/mage/cards/n/NineLives.java +++ b/Mage.Sets/src/mage/cards/n/NineLives.java @@ -15,12 +15,8 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; -import mage.players.Player; import java.util.UUID; @@ -74,20 +70,11 @@ class NineLivesPreventionEffect 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 damage = event.getAmount(); - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Permanent nineLives = source.getSourcePermanentIfItStillExists(game); - if (nineLives != null) { - nineLives.addCounters(CounterType.INCARNATION.createInstance(1), source.getControllerId(), source, game); - } - } - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); + Permanent nineLives = source.getSourcePermanentIfItStillExists(game); + if (nineLives != null) { + nineLives.addCounters(CounterType.INCARNATION.createInstance(1), source.getControllerId(), source, game); } - return false; + return super.replaceEvent(event, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java b/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java deleted file mode 100644 index 4d65ecdf45c..00000000000 --- a/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java +++ /dev/null @@ -1,128 +0,0 @@ -package mage.cards.n; - -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.NissaSageAnimistToken; -import mage.game.permanent.token.custom.CreatureToken; -import mage.players.Player; -import mage.target.common.TargetLandPermanent; -import mage.target.targetpointer.FixedTarget; - -/** - * - * @author emerald000 - */ -public final class NissaSageAnimist extends CardImpl { - - public NissaSageAnimist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.NISSA); - this.color.setGreen(true); - - this.nightCard = true; - - 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)); - - // -2: Create a legendary 4/4 green Elemental creature token named Ashaya, the Awoken World. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new NissaSageAnimistToken()), -2)); - - // -7: Untap up to six target lands. They become 6/6 Elemental creatures. They're still lands. - Ability ability = new LoyaltyAbility(new UntapTargetEffect(), -7); - ability.addTarget(new TargetLandPermanent(0, 6)); - ability.addEffect(new NissaSageAnimistMinusAnimateEffect()); - this.addAbility(ability); - } - - private NissaSageAnimist(final NissaSageAnimist card) { - super(card); - } - - @Override - public NissaSageAnimist copy() { - return new NissaSageAnimist(this); - } -} - -class NissaSageAnimistPlusOneEffect extends OneShotEffect { - - NissaSageAnimistPlusOneEffect() { - super(Outcome.Benefit); - this.staticText = "Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand."; - } - - private NissaSageAnimistPlusOneEffect(final NissaSageAnimistPlusOneEffect effect) { - super(effect); - } - - @Override - public NissaSageAnimistPlusOneEffect copy() { - return new NissaSageAnimistPlusOneEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); - if (sourceObject != null && controller != null && controller.getLibrary().hasCards()) { - Card card = controller.getLibrary().getFromTop(game); - if (card == null) { - return false; - } - controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); - Zone targetZone = Zone.HAND; - if (card.isLand(game)) { - targetZone = Zone.BATTLEFIELD; - } - return controller.moveCards(card, targetZone, source, game); - } - return true; - } -} - -class NissaSageAnimistMinusAnimateEffect extends OneShotEffect { - - NissaSageAnimistMinusAnimateEffect() { - super(Outcome.BecomeCreature); - this.staticText = "They become 6/6 Elemental creatures. They're still lands"; - } - - private NissaSageAnimistMinusAnimateEffect(final NissaSageAnimistMinusAnimateEffect effect) { - super(effect); - } - - @Override - public NissaSageAnimistMinusAnimateEffect copy() { - return new NissaSageAnimistMinusAnimateEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID permanentId : this.getTargetPointer().getTargets(game, source)) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { - ContinuousEffectImpl effect = new BecomesCreatureTargetEffect(new CreatureToken(6, 6, "", SubType.ELEMENTAL), false, true, Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java b/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java index 01b027d210d..19a00564534 100644 --- a/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java +++ b/Mage.Sets/src/mage/cards/n/NissaVastwoodSeer.java @@ -1,27 +1,42 @@ package mage.cards.n; -import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LandfallAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterBasicCard; import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.NissaSageAnimistToken; +import mage.game.permanent.token.custom.CreatureToken; +import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetLandPermanent; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author emerald000 */ -public final class NissaVastwoodSeer extends CardImpl { +public final class NissaVastwoodSeer extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterBasicCard(SubType.FOREST); @@ -31,25 +46,39 @@ public final class NissaVastwoodSeer extends CardImpl { ); public NissaVastwoodSeer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.SCOUT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELF, SubType.SCOUT}, "{2}{G}", + "Nissa, Sage Animist", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.NISSA}, "G" + ); - this.secondSideCardClazz = mage.cards.n.NissaSageAnimist.class; + // Nissa, Vastwood Seer + this.getLeftHalfCard().setPT(2, 2); // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true )); // Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new LandfallAbility(new ExileAndReturnSourceEffect( + this.getLeftHalfCard().addAbility(new LandfallAbility(new ExileAndReturnSourceEffect( PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE )).withInterveningIf(condition).setAbilityWord(null)); + + // Nissa, Sage Animist + this.getRightHalfCard().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.getRightHalfCard().addAbility(new LoyaltyAbility(new NissaSageAnimistPlusOneEffect(), 1)); + + // -2: Create a legendary 4/4 green Elemental creature token named Ashaya, the Awoken World. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new NissaSageAnimistToken()), -2)); + + // -7: Untap up to six target lands. They become 6/6 Elemental creatures. They're still lands. + Ability ability = new LoyaltyAbility(new UntapTargetEffect(), -7); + ability.addTarget(new TargetLandPermanent(0, 6)); + ability.addEffect(new NissaSageAnimistMinusAnimateEffect()); + this.getRightHalfCard().addAbility(ability); } private NissaVastwoodSeer(final NissaVastwoodSeer card) { @@ -61,3 +90,69 @@ public final class NissaVastwoodSeer extends CardImpl { return new NissaVastwoodSeer(this); } } + +class NissaSageAnimistPlusOneEffect extends OneShotEffect { + + NissaSageAnimistPlusOneEffect() { + super(Outcome.Benefit); + this.staticText = "Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand."; + } + + private NissaSageAnimistPlusOneEffect(final NissaSageAnimistPlusOneEffect effect) { + super(effect); + } + + @Override + public NissaSageAnimistPlusOneEffect copy() { + return new NissaSageAnimistPlusOneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source); + if (sourceObject != null && controller != null && controller.getLibrary().hasCards()) { + Card card = controller.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); + Zone targetZone = Zone.HAND; + if (card.isLand(game)) { + targetZone = Zone.BATTLEFIELD; + } + return controller.moveCards(card, targetZone, source, game); + } + return true; + } +} + +class NissaSageAnimistMinusAnimateEffect extends OneShotEffect { + + NissaSageAnimistMinusAnimateEffect() { + super(Outcome.BecomeCreature); + this.staticText = "They become 6/6 Elemental creatures. They're still lands"; + } + + private NissaSageAnimistMinusAnimateEffect(final NissaSageAnimistMinusAnimateEffect effect) { + super(effect); + } + + @Override + public NissaSageAnimistMinusAnimateEffect copy() { + return new NissaSageAnimistMinusAnimateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID permanentId : this.getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + ContinuousEffectImpl effect = new BecomesCreatureTargetEffect(new CreatureToken(6, 6, "", SubType.ELEMENTAL), false, true, Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NivMizzetGuildpact.java b/Mage.Sets/src/mage/cards/n/NivMizzetGuildpact.java index 2c12aaf71c7..e6336262de4 100644 --- a/Mage.Sets/src/mage/cards/n/NivMizzetGuildpact.java +++ b/Mage.Sets/src/mage/cards/n/NivMizzetGuildpact.java @@ -52,7 +52,6 @@ public final class NivMizzetGuildpact extends CardImpl { // Whenever Niv-Mizzet, Guildpact deals combat damage to a player, it deals X damage to any target, target player draws X cards, and you gain X life, where X is the number of different color pairs among permanents you control that are exactly two colors. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( new DamageTargetEffect(NivMizzetGuildpactCount.instance) - .setUseOnlyTargetPointer(true) .setText("it deals X damage to any target"), false); ability.addTarget(new TargetAnyTarget()); ability.addEffect(new DrawCardTargetEffect(NivMizzetGuildpactCount.instance) diff --git a/Mage.Sets/src/mage/cards/n/NoctisHeirApparent.java b/Mage.Sets/src/mage/cards/n/NoctisHeirApparent.java new file mode 100644 index 00000000000..086d41519a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NoctisHeirApparent.java @@ -0,0 +1,167 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsPhaseCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachTargetToTargetEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +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.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NoctisHeirApparent extends CardImpl { + + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + + public NoctisHeirApparent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever a creature you control enters during combat, you may attach target Equipment you control to target creature you control. + Ability ability = new EntersBattlefieldAllTriggeredAbility( + new AttachTargetToTargetEffect(), StaticFilters.FILTER_CONTROLLED_CREATURE, true + ).withTriggerCondition(condition); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // Warp-Strike -- {3}: Exile Noctis. Return it to the battlefield under its owner's control tapped and attacking at the beginning of that player's next declare attackers step. It can't be blocked that combat. + this.addAbility(new SimpleActivatedAbility(new NoctisHeirApparentExileEffect(), new GenericManaCost(3)).withFlavorWord("Warp-Strike")); + } + + private NoctisHeirApparent(final NoctisHeirApparent card) { + super(card); + } + + @Override + public NoctisHeirApparent copy() { + return new NoctisHeirApparent(this); + } +} + +class NoctisHeirApparentExileEffect extends OneShotEffect { + + NoctisHeirApparentExileEffect() { + super(Outcome.Benefit); + staticText = "Exile {this}. Return it to the battlefield under its owner's control tapped and attacking " + + "at the beginning of that player's next declare attackers step. It can't be blocked that combat."; + } + + private NoctisHeirApparentExileEffect(final NoctisHeirApparentExileEffect effect) { + super(effect); + } + + @Override + public NoctisHeirApparentExileEffect copy() { + return new NoctisHeirApparentExileEffect(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; + } + player.moveCards(permanent, Zone.EXILED, source, game); + game.addDelayedTriggeredAbility(new NoctisHeirApparentTriggeredAbility(permanent, game), source); + return true; + } +} + +class NoctisHeirApparentTriggeredAbility extends DelayedTriggeredAbility { + + private final UUID playerId; + + NoctisHeirApparentTriggeredAbility(Permanent permanent, Game game) { + super(new NoctisHeirApparentReturnEffect(permanent, game), Duration.Custom, true, false); + this.playerId = permanent.getOwnerId(); + } + + private NoctisHeirApparentTriggeredAbility(final NoctisHeirApparentTriggeredAbility ability) { + super(ability); + this.playerId = ability.playerId; + } + + @Override + public NoctisHeirApparentTriggeredAbility copy() { + return new NoctisHeirApparentTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(playerId); + } + + @Override + public String getRule() { + return "Return it to the battlefield under its owner's control tapped and attacking at " + + "the beginning of that player's next declare attackers step. It can't be blocked that combat."; + } +} + +class NoctisHeirApparentReturnEffect extends OneShotEffect { + + NoctisHeirApparentReturnEffect(Permanent permanent, Game game) { + super(Outcome.Benefit); + this.setTargetPointer(new FixedTarget(permanent.getId(), game)); + } + + private NoctisHeirApparentReturnEffect(final NoctisHeirApparentReturnEffect effect) { + super(effect); + } + + @Override + public NoctisHeirApparentReturnEffect copy() { + return new NoctisHeirApparentReturnEffect(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, true, false, true, null); + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent == null) { + return true; + } + game.getCombat().addAttackingCreature(permanent.getId(), game); + game.addEffect(new CantBeBlockedTargetEffect(Duration.EndOfCombat) + .setTargetPointer(new FixedTarget(permanent, game)), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NorthPoleGates.java b/Mage.Sets/src/mage/cards/n/NorthPoleGates.java new file mode 100644 index 00000000000..781b54b77c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NorthPoleGates.java @@ -0,0 +1,48 @@ +package mage.cards.n; + +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.GenericManaCost; +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 NorthPoleGates extends CardImpl { + + public NorthPoleGates(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W} or {U}. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlueManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private NorthPoleGates(final NorthPoleGates card) { + super(card); + } + + @Override + public NorthPoleGates copy() { + return new NorthPoleGates(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NorthPolePatrol.java b/Mage.Sets/src/mage/cards/n/NorthPolePatrol.java new file mode 100644 index 00000000000..e7717bdfd4d --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NorthPolePatrol.java @@ -0,0 +1,54 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.WaterbendCost; +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.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NorthPolePatrol extends CardImpl { + + public NorthPolePatrol(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {T}: Untap another target permanent you control. + Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_TARGET_PERMANENT)); + this.addAbility(ability); + + // Waterbend {3}, {T}: Tap target creature an opponent controls. + ability = new SimpleActivatedAbility(new TapTargetEffect(), new WaterbendCost(3)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private NorthPolePatrol(final NorthPolePatrol card) { + super(card); + } + + @Override + public NorthPolePatrol copy() { + return new NorthPolePatrol(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NorthernAirTemple.java b/Mage.Sets/src/mage/cards/n/NorthernAirTemple.java new file mode 100644 index 00000000000..6f92b379e66 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NorthernAirTemple.java @@ -0,0 +1,49 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +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 NorthernAirTemple extends CardImpl { + + public NorthernAirTemple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // When Northern Air Temple enters, each opponent loses X life and you gain X life, where X is the number of Shrines you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeOpponentsEffect(ShrinesYouControlCount.WHERE_X) + .setText("each opponent loses X life")); + ability.addEffect(new GainLifeEffect(ShrinesYouControlCount.WHERE_X).setText("and you gain X life, where X is the number of Shrines you control")); + this.addAbility(ability.addHint(ShrinesYouControlCount.getHint())); + + // Whenever another Shrine you control enters, each opponent loses 1 life and you gain 1 life. + ability = new EntersBattlefieldAllTriggeredAbility(new LoseLifeOpponentsEffect(1), StaticFilters.FILTER_ANOTHER_CONTROLLED_SHRINE); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private NorthernAirTemple(final NorthernAirTemple card) { + super(card); + } + + @Override + public NorthernAirTemple copy() { + return new NorthernAirTemple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java b/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java new file mode 100644 index 00000000000..9b293cc893c --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NylaShirshuSleuth.java @@ -0,0 +1,134 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +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.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.players.Player; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NylaShirshuSleuth extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent(SubType.CLUE, "you control no Clues"), ComparisonType.EQUAL_TO, 0 + ); + private static final Hint hint = new ValueHint( + "Clues you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.CLUE)) + ); + private static final FilterCard filter = new FilterCard("card exiled with this permanent"); + + static { + filter.add(NylaShirshuSleuthPredicate.instance); + } + + public NylaShirshuSleuth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MOLE); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Nyla enters, exile up to one target creature card from your graveyard. If you do, you lose X life and create X Clue tokens, where X is that card's mana value. + Ability ability = new EntersBattlefieldTriggeredAbility(new NylaShirshuSleuthEffect()); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // At the beginning of your end step, if you control no Clues, return target card exiled with Nyla to its owner's hand. + ability = new BeginningOfEndStepTriggeredAbility(new ReturnToHandTargetEffect() + .setText("return target card exiled with {this} to its owner's hand")) + .withInterveningIf(condition) + .addHint(hint); + ability.addTarget(new TargetCardInExile(filter)); + this.addAbility(ability); + } + + private NylaShirshuSleuth(final NylaShirshuSleuth card) { + super(card); + } + + @Override + public NylaShirshuSleuth copy() { + return new NylaShirshuSleuth(this); + } +} + +enum NylaShirshuSleuthPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return Optional + .ofNullable(input) + .map(ObjectSourcePlayer::getSource) + .map(source -> CardUtil.getExileZoneId(game, source)) + .map(game.getState().getExile()::getExileZone) + .filter(exile -> exile.contains(input.getObject().getId())) + .isPresent(); + } +} + +class NylaShirshuSleuthEffect extends OneShotEffect { + + NylaShirshuSleuthEffect() { + super(Outcome.Benefit); + staticText = "exile up to one target creature card from your graveyard. " + + "If you do, you lose X life and create X Clue tokens, where X is that card's mana value"; + } + + private NylaShirshuSleuthEffect(final NylaShirshuSleuthEffect effect) { + super(effect); + } + + @Override + public NylaShirshuSleuthEffect copy() { + return new NylaShirshuSleuthEffect(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; + } + int mv = card.getManaValue(); + player.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + if (mv > 0) { + player.loseLife(mv, game, source, false); + new ClueArtifactToken().putOntoBattlefield(mv, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java b/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java deleted file mode 100644 index d20338dc62a..00000000000 --- a/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java +++ /dev/null @@ -1,120 +0,0 @@ -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.withNotTarget(true); - player.choose(Outcome.ReturnToHand, controller.getGraveyard(), target, source, 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/OakshadeStalker.java b/Mage.Sets/src/mage/cards/o/OakshadeStalker.java index ca4969bf919..f78a0ac4bac 100644 --- a/Mage.Sets/src/mage/cards/o/OakshadeStalker.java +++ b/Mage.Sets/src/mage/cards/o/OakshadeStalker.java @@ -1,11 +1,11 @@ package mage.cards.o; -import mage.MageInt; import mage.abilities.common.PayMoreToCastAsThoughtItHadFlashAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,23 +14,28 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class OakshadeStalker extends CardImpl { +public final class OakshadeStalker extends TransformingDoubleFacedCard { public OakshadeStalker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.RANGER, SubType.WEREWOLF}, "{2}{G}", + "Moonlit Ambusher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.RANGER); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.m.MoonlitAmbusher.class; + // Oakshade Stalker + this.getLeftHalfCard().setPT(3, 3); // You may cast this spell as though it had flash if you pay {2} more to cast it. - this.addAbility(new PayMoreToCastAsThoughtItHadFlashAbility(this, new ManaCostsImpl<>("{2}"))); + this.getLeftHalfCard().addAbility(new PayMoreToCastAsThoughtItHadFlashAbility(this.getLeftHalfCard(), new ManaCostsImpl<>("{2}"))); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Moonlit Ambusher + this.getRightHalfCard().setPT(6, 3); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private OakshadeStalker(final OakshadeStalker card) { diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java index 09a51a27ee6..7cf043ecee2 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java @@ -28,9 +28,8 @@ public final class ObNixilisTheHateTwisted extends CardImpl { 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, true, "that player" - ), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1) + .withTargetDescription("that player"), false, true)); // -2: Destroy target creature. Its controller draws two cards. Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -2); diff --git a/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java b/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java new file mode 100644 index 00000000000..39fa5c31463 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObsessivePursuit.java @@ -0,0 +1,74 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetAttackingCreature; +import mage.watchers.common.PermanentsSacrificedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObsessivePursuit extends CardImpl { + + public ObsessivePursuit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + // When this enchantment enters and at the beginning of your upkeep, you lose 1 life and create a Clue token. + Ability ability = new OrTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeSourceControllerEffect(1), + new EntersBattlefieldTriggeredAbility(null), new BeginningOfUpkeepTriggeredAbility(null) + ).setTriggerPhrase("When {this} enters and at the beginning of your upkeep, "); + ability.addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("and")); + this.addAbility(ability); + + // Whenever you attack, put X +1/+1 counters on target attacking creature, where X is the number of permanents you've sacrificed this turn. If X is three or greater, that creature gains lifelink until end of turn. + ability = new AttacksWithCreaturesTriggeredAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(), PermanentsSacrificedThisTurnCount.YOU + ), 1).addHint(PermanentsSacrificedThisTurnCount.YOU.getHint()); + ability.addEffect(new ConditionalOneShotEffect( + new AddContinuousEffectToGame(new GainAbilityTargetEffect(LifelinkAbility.getInstance())), + ObsessivePursuitCondition.instance, "If X is three or greater, that creature gains lifelink until end of turn" + )); + ability.addTarget(new TargetAttackingCreature()); + this.addAbility(ability, new PermanentsSacrificedWatcher()); + } + + private ObsessivePursuit(final ObsessivePursuit card) { + super(card); + } + + @Override + public ObsessivePursuit copy() { + return new ObsessivePursuit(this); + } +} + +enum ObsessivePursuitCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return PermanentsSacrificedThisTurnCount.YOU.calculate(game, source, null) >= 3; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OctopusForm.java b/Mage.Sets/src/mage/cards/o/OctopusForm.java new file mode 100644 index 00000000000..c54d9353204 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OctopusForm.java @@ -0,0 +1,45 @@ +package mage.cards.o; + +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +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.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OctopusForm extends CardImpl { + + public OctopusForm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + this.subtype.add(SubType.LESSON); + + // Target creature you control gets +1/+1 and gains hexproof until end of turn. Untap it. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 1, Duration.EndOfTurn + ).setText("target creature you control gets +1/+1")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains hexproof until end of turn")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addEffect(new UntapTargetEffect("Untap it")); + } + + private OctopusForm(final OctopusForm card) { + super(card); + } + + @Override + public OctopusForm copy() { + return new OctopusForm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OdiousWitch.java b/Mage.Sets/src/mage/cards/o/OdiousWitch.java deleted file mode 100644 index 253b38f0029..00000000000 --- a/Mage.Sets/src/mage/cards/o/OdiousWitch.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -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.SetTargetPointer; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class OdiousWitch extends CardImpl { - - public OdiousWitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Whenever Odious Witch attacks, defending player loses 1 life and you gain 1 life. - Ability ability = new AttacksTriggeredAbility( - new LoseLifeTargetEffect(1) - .setText("defending player loses 1 life"), - false, null, SetTargetPointer.PLAYER - ); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private OdiousWitch(final OdiousWitch card) { - super(card); - } - - @Override - public OdiousWitch copy() { - return new OdiousWitch(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OjerAxonilDeepestMight.java b/Mage.Sets/src/mage/cards/o/OjerAxonilDeepestMight.java index a4640a9186d..8c7bbe6e8bd 100644 --- a/Mage.Sets/src/mage/cards/o/OjerAxonilDeepestMight.java +++ b/Mage.Sets/src/mage/cards/o/OjerAxonilDeepestMight.java @@ -1,50 +1,74 @@ package mage.cards.o; -import mage.MageInt; + import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.Hint; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.RedManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Controllable; import mage.game.Game; +import mage.game.command.CommandObject; import mage.game.events.DamageEvent; +import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; import mage.players.Player; +import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; /** * @author Susucr */ -public final class OjerAxonilDeepestMight extends CardImpl { +public final class OjerAxonilDeepestMight extends TransformingDoubleFacedCard { public OjerAxonilDeepestMight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); - this.secondSideCardClazz = mage.cards.t.TempleOfPower.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{2}{R}{R}", + "Temple of Power", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + // Ojer Axonil, Deepest Might + this.getLeftHalfCard().setPT(4, 4); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // If a red source you control would deal an amount of noncombat damage less than Ojer Axonil's power to an opponent, that source deals damage equal to Ojer Axonil's power instead. - this.addAbility(new SimpleStaticAbility(new OjerAxonilDeepestMightReplacementEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new OjerAxonilDeepestMightReplacementEffect())); // When Ojer Axonil dies, return it to the battlefield tapped and transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new OjerAxonilDeepestMightTransformEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OjerAxonilDeepestMightTransformEffect())); + + // Temple of Power + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); + + // {2}{R}, {T}: Transform Temple of Power. Activate only if red sources you controlled dealt 4 or more noncombat damage this turn and only as a sorcery. + Ability ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{R}"), TempleOfPowerCondition.instance + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + ability.addWatcher(new TempleOfPowerWatcher()); + this.getRightHalfCard().addAbility(ability.addHint(TempleOfPowerHint.instance)); } private OjerAxonilDeepestMight(final OjerAxonilDeepestMight card) { @@ -155,3 +179,100 @@ class OjerAxonilDeepestMightReplacementEffect extends ReplacementEffectImpl { && event.getAmount() < ojer.getPower().getValue(); } } + +enum TempleOfPowerCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + TempleOfPowerWatcher watcher = game.getState().getWatcher(TempleOfPowerWatcher.class); + return watcher != null + && 4 <= watcher.damageForPlayer(source.getControllerId()); + } + + @Override + public String toString() { + return "red sources you controlled dealt 4 or more noncombat damage this turn"; + } +} + +enum TempleOfPowerHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + TempleOfPowerWatcher watcher = game.getState().getWatcher(TempleOfPowerWatcher.class); + if (watcher == null) { + return ""; + } + + return "Non-combat damage from red source: " + + watcher.damageForPlayer(ability.getControllerId()); + } + + @Override + public TempleOfPowerHint copy() { + return instance; + } +} + +class TempleOfPowerWatcher extends Watcher { + + // player -> total non combat damage from red source controlled by that player dealt this turn. + private final Map damageMap = new HashMap<>(); + + public TempleOfPowerWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER + || event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { + DamagedEvent dmgEvent = (DamagedEvent) event; + + // watch only non combat damage events. + if (dmgEvent == null || dmgEvent.isCombatDamage()) { + return; + } + + MageObject sourceObject; + UUID sourceControllerId = null; + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (sourcePermanent != null) { + // source is a permanent. + sourceObject = sourcePermanent; + sourceControllerId = sourcePermanent.getControllerId(); + } else { + sourceObject = game.getSpellOrLKIStack(event.getSourceId()); + if (sourceObject != null) { + // source is a spell. + sourceControllerId = ((StackObject) sourceObject).getControllerId(); + } else { + sourceObject = game.getObject(event.getSourceId()); + if (sourceObject instanceof CommandObject) { + // source is a Command Object. For instance Emblem + sourceControllerId = ((CommandObject) sourceObject).getControllerId(); + } + } + } + + // watch only red sources dealing damage + if (sourceObject == null || sourceControllerId == null || !sourceObject.getColor().isRed()) { + return; + } + + damageMap.compute(sourceControllerId, (k, i) -> (i == null ? 0 : i) + event.getAmount()); + } + } + + @Override + public void reset() { + damageMap.clear(); + super.reset(); + } + + int damageForPlayer(UUID playerId) { + return damageMap.getOrDefault(playerId, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OjerKaslemDeepestGrowth.java b/Mage.Sets/src/mage/cards/o/OjerKaslemDeepestGrowth.java index 67222a03623..6538489b745 100644 --- a/Mage.Sets/src/mage/cards/o/OjerKaslemDeepestGrowth.java +++ b/Mage.Sets/src/mage/cards/o/OjerKaslemDeepestGrowth.java @@ -1,15 +1,23 @@ package mage.cards.o; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.PermanentsYouControlHint; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.GreenManaAbility; import mage.cards.*; +import mage.cards.g.GishathSunsAvatar; import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; @@ -20,26 +28,39 @@ import java.util.UUID; /** * @author Susucr */ -public final class OjerKaslemDeepestGrowth extends CardImpl { +public final class OjerKaslemDeepestGrowth extends TransformingDoubleFacedCard { public OjerKaslemDeepestGrowth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); - this.secondSideCardClazz = mage.cards.t.TempleOfCultivation.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{3}{G}{G}", + "Temple of Cultivation", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(6); - this.toughness = new MageInt(5); + // Ojer Kaslem, Deepest Growth + this.getLeftHalfCard().setPT(6, 5); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // Whenever Ojer Kaslem deals combat damage to a player, reveal that many cards from the top of your library. You may put a creature card and/or a land card from among them onto the battlefield. Put the rest on the bottom in a random order. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new OjerKaslemDeepestGrowthEffect(), false, true)); + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new OjerKaslemDeepestGrowthEffect(), false, true)); // When Ojer Kaslem dies, return it to the battlefield tapped and transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new OjerKaslemDeepestGrowthTransformEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OjerKaslemDeepestGrowthTransformEffect())); + + // Temple of Cultivation + // {T}: Add {G}. + this.getRightHalfCard().addAbility(new GreenManaAbility()); + + // {2}{G}, {T}: Transform Temple of Cultivation. Activate only if you control ten or more permanents and only as a sorcery. + Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledPermanent("you control ten or more permanents"), ComparisonType.MORE_THAN, 9 + ); + Ability ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{G}"), condition + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability.addHint(PermanentsYouControlHint.instance)); } private OjerKaslemDeepestGrowth(final OjerKaslemDeepestGrowth card) { @@ -82,7 +103,7 @@ class OjerKaslemDeepestGrowthTransformEffect extends OneShotEffect { } /** - * Inspired by {@link mage.cards.g.GishathSunsAvatar} + * Inspired by {@link GishathSunsAvatar} */ class OjerKaslemDeepestGrowthEffect extends OneShotEffect { @@ -116,7 +137,7 @@ class OjerKaslemDeepestGrowthEffect extends OneShotEffect { controller.choose(Outcome.PutCardInPlay, cards, target, source, game); Cards toBattlefield = new CardsImpl(target.getTargets()); cards.removeAll(toBattlefield); - controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, false, false, false, null); + controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game); controller.putCardsOnBottomOfLibrary(cards, game, source, false); } return true; diff --git a/Mage.Sets/src/mage/cards/o/OjerPakpatiqDeepestEpoch.java b/Mage.Sets/src/mage/cards/o/OjerPakpatiqDeepestEpoch.java index c302c5a021f..73a4be11c49 100644 --- a/Mage.Sets/src/mage/cards/o/OjerPakpatiqDeepestEpoch.java +++ b/Mage.Sets/src/mage/cards/o/OjerPakpatiqDeepestEpoch.java @@ -1,18 +1,25 @@ package mage.cards.o; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReboundAbility; import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.BlueManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.n.NarsetTranscendent; import mage.constants.*; import mage.counters.CounterType; import mage.counters.Counters; @@ -26,35 +33,48 @@ import java.util.UUID; /** * @author Susucr */ -public final class OjerPakpatiqDeepestEpoch extends CardImpl { +public final class OjerPakpatiqDeepestEpoch extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("an instant spell"); + private static final Condition condition = new SourceHasCounterCondition(CounterType.TIME, ComparisonType.EQUAL_TO, 0); static { filter.add(CardType.INSTANT.getPredicate()); } public OjerPakpatiqDeepestEpoch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); - this.secondSideCardClazz = mage.cards.t.TempleOfCyclicalTime.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{2}{U}{U}", + "Temple of Cyclical Time", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(4); - this.toughness = new MageInt(3); + // Ojer Pakpatiq, Deepest Epoch + this.getLeftHalfCard().setPT(4, 3); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever you cast an instant spell from your hand, it gains rebound. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( Zone.BATTLEFIELD, new OjerPakpatiqDeepestEpochGainReboundEffect(), filter, false, SetTargetPointer.SPELL, Zone.HAND )); // When Ojer Pakpatiq dies, return it to the battlefield tapped and transformed under its owner's control with three time counters on it. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new OjerPakpatiqDeepestEpochTrigger())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OjerPakpatiqDeepestEpochTrigger())); + + // Temple of Cyclical Time + // {T}: Add {U}. Remove a time counter from Temple of Cyclical Time. + Ability ability = new BlueManaAbility(); + ability.addEffect(new RemoveCounterSourceEffect(CounterType.TIME.createInstance())); + this.getRightHalfCard().addAbility(ability); + + // {2}{U}, {T}: Transform Temple of Cyclical Time. Activate only if it has no time counters on it and only as a sorcery. + ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{U}"), condition + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); } private OjerPakpatiqDeepestEpoch(final OjerPakpatiqDeepestEpoch card) { @@ -68,7 +88,7 @@ public final class OjerPakpatiqDeepestEpoch extends CardImpl { } /** - * Inspired by {@link mage.cards.n.NarsetTranscendent} + * Inspired by {@link NarsetTranscendent} */ class OjerPakpatiqDeepestEpochGainReboundEffect extends ContinuousEffectImpl { diff --git a/Mage.Sets/src/mage/cards/o/OjerTaqDeepestFoundation.java b/Mage.Sets/src/mage/cards/o/OjerTaqDeepestFoundation.java index 21ff3486692..1241a2425e7 100644 --- a/Mage.Sets/src/mage/cards/o/OjerTaqDeepestFoundation.java +++ b/Mage.Sets/src/mage/cards/o/OjerTaqDeepestFoundation.java @@ -1,48 +1,64 @@ package mage.cards.o; -import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; import mage.players.Player; +import mage.watchers.common.PlayerAttackedWatcher; import java.util.UUID; /** * @author Susucr */ -public final class OjerTaqDeepestFoundation extends CardImpl { +public final class OjerTaqDeepestFoundation extends TransformingDoubleFacedCard { public OjerTaqDeepestFoundation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); - this.secondSideCardClazz = mage.cards.t.TempleOfCivilization.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "{4}{W}{W}", + "Temple of Civilization", + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.GOD); - this.power = new MageInt(6); - this.toughness = new MageInt(6); + // Ojer Taq, Deepest Foundation + this.getLeftHalfCard().setPT(6, 6); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // If one or more creature tokens would be created under your control, three times that many of those tokens are created instead. - this.addAbility(new SimpleStaticAbility(new OjerTaqDeepestFoundationTriplingEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new OjerTaqDeepestFoundationTriplingEffect())); // When Ojer Taq dies, return it to the battlefield tapped and transformed under its owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesSourceTriggeredAbility(new OjerTaqDeepestFoundationTransformEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OjerTaqDeepestFoundationTransformEffect())); + + // Temple of Civilization + // {T}: Add {W}. + this.getRightHalfCard().addAbility(new WhiteManaAbility()); + + // {2}{W}, {T}: Transform Temple of Civilization. Activate only if you attacked with three or more creatures this turn and only as a sorcery. + Ability ability = new ActivateIfConditionActivatedAbility( + new TransformSourceEffect(), new ManaCostsImpl<>("{2}{W}"), TempleOfCivilizationCondition.instance + ).setTiming(TimingRule.SORCERY); + ability.addCost(new TapSourceCost()); + ability.addWatcher(new PlayerAttackedWatcher()); + this.getRightHalfCard().addAbility(ability); } private OjerTaqDeepestFoundation(final OjerTaqDeepestFoundation card) { @@ -124,3 +140,18 @@ class OjerTaqDeepestFoundationTriplingEffect extends ReplacementEffectImpl { return false; } } + +enum TempleOfCivilizationCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + PlayerAttackedWatcher watcher = game.getState().getWatcher(PlayerAttackedWatcher.class); + return watcher != null && watcher.getNumberOfAttackersCurrentTurn(source.getControllerId()) >= 3; + } + + @Override + public String toString() { + return "you attacked with three or more creatures this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OkibaReckonerRaid.java b/Mage.Sets/src/mage/cards/o/OkibaReckonerRaid.java index ef5f69bdea1..988e0b33893 100644 --- a/Mage.Sets/src/mage/cards/o/OkibaReckonerRaid.java +++ b/Mage.Sets/src/mage/cards/o/OkibaReckonerRaid.java @@ -1,36 +1,45 @@ package mage.cards.o; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; +import mage.filter.FilterPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class OkibaReckonerRaid extends CardImpl { +public final class OkibaReckonerRaid extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent(SubType.VEHICLE, "Vehicles"); public OkibaReckonerRaid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{B}", + "Nezumi Road Captain", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.RAT, SubType.ROGUE}, "B"); - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.n.NezumiRoadCaptain.class; + // Okiba Reckoner Raid + this.getRightHalfCard().setPT(2, 2); // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Each opponent loses 1 life and you gain 1 life. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new Effects( new LoseLifeOpponentsEffect(1), new GainLifeEffect(1).concatBy("and") @@ -38,10 +47,18 @@ public final class OkibaReckonerRaid extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Nezumi Road Captain + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Vehicles you control have menace. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(true), Duration.WhileOnBattlefield, filter) + )); } private OkibaReckonerRaid(final OkibaReckonerRaid card) { diff --git a/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java b/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java deleted file mode 100644 index 9b9a6abc671..00000000000 --- a/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java +++ /dev/null @@ -1,141 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.CopyEffect; -import mage.cards.*; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentCard; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; -import mage.util.CardUtil; -import mage.util.functions.CopyApplier; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class OlagLudevicsHubris extends CardImpl { - - public OlagLudevicsHubris(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ZOMBIE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // As this creature transforms in Olag, Ludevic's Hubris, it becomes a copy of a creature card exiled with it, except its name is Olag, Ludevic's Hubris, it's 4/4, and it's a legendary blue and black Zombie in addition to its other colors and types. Put a number of +1/+1 counters on Olag equal to the number of creature cards exiled with it. - this.addAbility(new SimpleStaticAbility(new OlagLudevicsHubrisEffect())); - } - - private OlagLudevicsHubris(final OlagLudevicsHubris card) { - super(card); - } - - @Override - public OlagLudevicsHubris copy() { - return new OlagLudevicsHubris(this); - } -} - -class OlagLudevicsHubrisEffect extends ReplacementEffectImpl { - - OlagLudevicsHubrisEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "as this creature transforms into {this}, it becomes a copy of a creature card exiled with it, " + - "except its name is Olag, Ludevic's Hubris, it's 4/4, and it's a legendary blue and black " + - "Zombie in addition to its other colors and types. Put a number of +1/+1 counters on {this} " + - "equal to the number of creature cards exiled with it"; - } - - private OlagLudevicsHubrisEffect(final OlagLudevicsHubrisEffect effect) { - super(effect); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); - if (exileZone == null) { - return false; - } - - Cards cards = new CardsImpl(exileZone); - cards.removeIf(uuid -> !game.getCard(uuid).isCreature(game)); - if (cards.isEmpty()) { - return false; - } - - Card copyFromCard = getCard(cards, source, game); - if (copyFromCard == null) { - return false; - } - Permanent newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); - newBluePrint.assignNewId(); - CopyApplier applier = new OlagLudevicsHubrisCopyApplier(); - applier.apply(game, newBluePrint, source, source.getSourceId()); - CopyEffect copyEffect = new CopyEffect(Duration.Custom, newBluePrint, source.getSourceId()); - copyEffect.setApplier(applier); - Ability newAbility = source.copy(); - copyEffect.init(newAbility, game); - game.addEffect(copyEffect, newAbility); - return false; - } - - private Card getCard(Cards cards, Ability source, Game game) { - if (cards.size() == 1) { - return cards.getRandom(game); - } - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return cards.getRandom(game); - } - TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); - player.choose(outcome, target, source, game); - return cards.get(target.getFirstTarget(), game); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.TRANSFORMING; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return source.getSourceId().equals(event.getTargetId()) - && source.getSourcePermanentIfItStillExists(game) != null; - } - - @Override - public OlagLudevicsHubrisEffect copy() { - return new OlagLudevicsHubrisEffect(this); - } -} - -class OlagLudevicsHubrisCopyApplier extends CopyApplier { - - @Override - public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { - blueprint.setName("Olag, Ludevic's Hubris"); - blueprint.addSuperType(SuperType.LEGENDARY); - blueprint.addSubType(SubType.ZOMBIE); - blueprint.getColor().setBlue(true); - blueprint.getColor().setBlack(true); - blueprint.getPower().setModifiedBaseValue(4); - blueprint.getToughness().setModifiedBaseValue(4); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/o/OmashuCity.java b/Mage.Sets/src/mage/cards/o/OmashuCity.java new file mode 100644 index 00000000000..eb1a89e64c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OmashuCity.java @@ -0,0 +1,48 @@ +package mage.cards.o; + +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.GenericManaCost; +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 OmashuCity extends CardImpl { + + public OmashuCity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {R} or {G}. + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private OmashuCity(final OmashuCity card) { + super(card); + } + + @Override + public OmashuCity copy() { + return new OmashuCity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OneOfThePack.java b/Mage.Sets/src/mage/cards/o/OneOfThePack.java deleted file mode 100644 index 40ce2562a2d..00000000000 --- a/Mage.Sets/src/mage/cards/o/OneOfThePack.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class OneOfThePack extends CardImpl { - - public OneOfThePack(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(6); - this.color.setGreen(true); - - this.nightCard = true; - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform One of the Pack. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private OneOfThePack(final OneOfThePack card) { - super(card); - } - - @Override - public OneOfThePack copy() { - return new OneOfThePack(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java deleted file mode 100644 index a3d53cfe4dc..00000000000 --- a/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java +++ /dev/null @@ -1,130 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.keyword.BolsterEffect; -import mage.abilities.keyword.LivingMetalAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author xenohedron - */ -public final class OptimusPrimeAutobotLeader extends CardImpl { - - public OptimusPrimeAutobotLeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(6); - this.toughness = new MageInt(8); - this.color.setWhite(true); - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime. - this.addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2) - .withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance())) - .withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect()) - .setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"), - 1)); - - // Transform Ability - this.addAbility(new TransformAbility()); - } - - private OptimusPrimeAutobotLeader(final OptimusPrimeAutobotLeader card) { - super(card); - } - - @Override - public OptimusPrimeAutobotLeader copy() { - return new OptimusPrimeAutobotLeader(this); - } -} - -class OptimusPrimeAutobotLeaderEffect extends OneShotEffect { - - OptimusPrimeAutobotLeaderEffect() { - super(Outcome.Transform); - } - - private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) { - super(effect); - } - - @Override - public OptimusPrimeAutobotLeaderEffect copy() { - return new OptimusPrimeAutobotLeaderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (creature == null) { - return false; - } - game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source); - return true; - } - -} - -class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility { - - private final MageObjectReference mor; - - OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) { - super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn); - this.mor = mor; - setTriggerPhrase("When that creature deals combat damage to a player this turn, "); - } - - private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) { - super(ability); - this.mor = ability.mor; - } - - @Override - public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() { - return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(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 (((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent permanent = game.getPermanent(event.getSourceId()); - return mor.refersTo(permanent, game); - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java index 833b7d03404..11a4d5db80c 100644 --- a/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java +++ b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java @@ -1,7 +1,13 @@ package mage.cards.o; -import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.LivingMetalAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -9,10 +15,14 @@ import mage.abilities.effects.keyword.BolsterEffect; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.TransformingDoubleFacedCardHalf; import mage.constants.*; import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import java.util.UUID; @@ -20,25 +30,40 @@ import java.util.UUID; /** * @author jbureau88 */ -public final class OptimusPrimeHero extends CardImpl { +public final class OptimusPrimeHero extends TransformingDoubleFacedCard { public OptimusPrimeHero(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}{R}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{3}{U}{R}{W}", + "Optimus Prime, Autobot Leader", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "WUR"); - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(4); - this.toughness = new MageInt(8); - this.secondSideCardClazz = mage.cards.o.OptimusPrimeAutobotLeader.class; + this.getLeftHalfCard().setPT(4, 8); + this.getRightHalfCard().setPT(6, 8); // More Than Meets the Eye {2}{U}{R}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}")); // At the beginning of each end step, bolster 1. - this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false)); + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false)); // When Optimus Prime dies, return it to the battlefield converted under its owner’s control. - this.addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect())); + this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect())); + + // Optimus Prime, Autobot Leader + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime. + this.getRightHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2) + .withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance())) + .withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect()) + .setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"), + 1)); } private OptimusPrimeHero(final OptimusPrimeHero card) { @@ -70,11 +95,81 @@ class OptimusPrimeHeroEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card card = game.getCard(source.getSourceId()); - if (card == null || controller == null) { + Card card = source.getSourceCardIfItStillExists(game); + if (controller == null || card == null) { return false; } - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - return controller.moveCards(card, Zone.BATTLEFIELD, source, game); + if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) { + return true; + } + Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide(); + if (backSide == null) { + return true; + } + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true); + controller.moveCards(backSide, Zone.BATTLEFIELD, source, game); + return true; + } +} + +class OptimusPrimeAutobotLeaderEffect extends OneShotEffect { + + OptimusPrimeAutobotLeaderEffect() { + super(Outcome.Transform); + } + + private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) { + super(effect); + } + + @Override + public OptimusPrimeAutobotLeaderEffect copy() { + return new OptimusPrimeAutobotLeaderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature == null) { + return false; + } + game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source); + return true; + } + +} + +class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private final MageObjectReference mor; + + OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) { + super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn); + this.mor = mor; + setTriggerPhrase("When that creature deals combat damage to a player this turn, "); + } + + private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) { + super(ability); + this.mor = ability.mor; + } + + @Override + public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() { + return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(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 (((DamagedPlayerEvent) event).isCombatDamage()) { + Permanent permanent = game.getPermanent(event.getSourceId()); + return mor.refersTo(permanent, game); + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/o/OrcishArtillery.java b/Mage.Sets/src/mage/cards/o/OrcishArtillery.java index c4589153f12..52f7b05ec24 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishArtillery.java +++ b/Mage.Sets/src/mage/cards/o/OrcishArtillery.java @@ -1,20 +1,18 @@ - package mage.cards.o; -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.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; 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 Plopman @@ -30,9 +28,8 @@ public final class OrcishArtillery extends CardImpl { this.toughness = new MageInt(3); // {tap}: Orcish Artillery deals 2 damage to any target and 3 damage to you. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(2, 3), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); - ability.addEffect(new DamageControllerEffect(3).setText("and 3 damage to you")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishCannonade.java b/Mage.Sets/src/mage/cards/o/OrcishCannonade.java index fe965ea9193..c33c70f1ae6 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishCannonade.java +++ b/Mage.Sets/src/mage/cards/o/OrcishCannonade.java @@ -1,16 +1,14 @@ - package mage.cards.o; -import java.util.UUID; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author LevelX2 @@ -21,11 +19,9 @@ public final class OrcishCannonade extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}{R}"); // Orcish Cannonade deals 2 damage to any target and 3 damage to you. - this.getSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getSpellAbility().addEffect(new DamageTargetAndYouEffect(2, 3)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - Effect effect = new DamageControllerEffect(3); - effect.setText("and 3 damage to you"); - this.getSpellAbility().addEffect(effect); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishCannoneers.java b/Mage.Sets/src/mage/cards/o/OrcishCannoneers.java index bf873ae3736..a2ad2abab8a 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishCannoneers.java +++ b/Mage.Sets/src/mage/cards/o/OrcishCannoneers.java @@ -1,21 +1,18 @@ - package mage.cards.o; -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.effects.Effect; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; 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 LoneFox @@ -31,10 +28,8 @@ public final class OrcishCannoneers extends CardImpl { this.toughness = new MageInt(3); // {tap}: Orcish Cannoneers deals 2 damage to any target and 3 damage to you. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); - Effect effect = new DamageControllerEffect(3); - effect.setText("and 3 damage to you"); - ability.addEffect(effect); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(2, 3), new TapSourceCost()); + ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishConscripts.java b/Mage.Sets/src/mage/cards/o/OrcishConscripts.java new file mode 100644 index 00000000000..7a6b84534e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrcishConscripts.java @@ -0,0 +1,105 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterBlockingCreature; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class OrcishConscripts extends CardImpl { + + public OrcishConscripts(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.ORC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Orcish Conscripts can't attack unless at least two other creatures attack. + this.addAbility(new SimpleStaticAbility(new OrcishConscriptsAttackEffect())); + + // Orcish Conscripts can't block unless at least two other creatures block. + this.addAbility(new SimpleStaticAbility(new OrcishConscriptsBlockEffect())); + } + + private OrcishConscripts(final OrcishConscripts card) { + super(card); + } + + @Override + public OrcishConscripts copy() { + return new OrcishConscripts(this); + } +} + +class OrcishConscriptsAttackEffect extends RestrictionEffect { + + OrcishConscriptsAttackEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack unless at least two other creatures attack"; + } + + private OrcishConscriptsAttackEffect(final OrcishConscriptsAttackEffect effect) { + super(effect); + } + + @Override + public OrcishConscriptsAttackEffect copy() { + return new OrcishConscriptsAttackEffect(this); + } + + @Override + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { + return numberOfAttackers > 2; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return source.getSourceId().equals(permanent.getId()); + } +} + +class OrcishConscriptsBlockEffect extends RestrictionEffect { + + private static final FilterBlockingCreature filter = new FilterBlockingCreature("Blocking creatures"); + + public OrcishConscriptsBlockEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't block unless at least two other creatures block"; + } + + private OrcishConscriptsBlockEffect(final OrcishConscriptsBlockEffect effect) { + super(effect); + } + + @Override + public OrcishConscriptsBlockEffect copy() { + return new OrcishConscriptsBlockEffect(this); + } + + @Override + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).size() <= 2; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrcishFarmer.java b/Mage.Sets/src/mage/cards/o/OrcishFarmer.java new file mode 100644 index 00000000000..60e3956e1bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrcishFarmer.java @@ -0,0 +1,78 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class OrcishFarmer extends CardImpl { + + public OrcishFarmer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + + this.subtype.add(SubType.ORC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {T}: Target land becomes a Swamp until its controller's next untap step. + Ability ability = new SimpleActivatedAbility(new OrcishFarmerEffect(), new TapSourceCost()); + ability.addTarget(new TargetLandPermanent()); + this.addAbility(ability); + } + + private OrcishFarmer(final OrcishFarmer card) { + super(card); + } + + @Override + public OrcishFarmer copy() { + return new OrcishFarmer(this); + } +} + +class OrcishFarmerEffect extends BecomesBasicLandTargetEffect { + + OrcishFarmerEffect() { + super(Duration.Custom, SubType.SWAMP); + setText("Target land becomes a Swamp until its controller's next untap step"); + } + + protected OrcishFarmerEffect(final OrcishFarmerEffect effect) { + super(effect); + } + + public OrcishFarmerEffect copy() { + return new OrcishFarmerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent p = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (p == null) { + discard(); + return false; + } + if (getEffectStartingOnTurn() != game.getTurnNum() + && game.isActivePlayer(p.getControllerId()) + && game.getStep().getType() == PhaseStep.UNTAP) { + discard(); + return false; + } + return super.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrderOfTheAlabasterHost.java b/Mage.Sets/src/mage/cards/o/OrderOfTheAlabasterHost.java deleted file mode 100644 index 32745385bf8..00000000000 --- a/Mage.Sets/src/mage/cards/o/OrderOfTheAlabasterHost.java +++ /dev/null @@ -1,41 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.abilities.common.BecomesBlockedByCreatureTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -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 OrderOfTheAlabasterHost extends CardImpl { - - public OrderOfTheAlabasterHost(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Whenever Order of the Alabaster Host becomes blocked by a creature, that creature gets -1/-1 until end of turn. - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new BoostTargetEffect(-1, -1).setText("that creature gets -1/-1 until end of turn"), false)); - } - - private OrderOfTheAlabasterHost(final OrderOfTheAlabasterHost card) { - super(card); - } - - @Override - public OrderOfTheAlabasterHost copy() { - return new OrderOfTheAlabasterHost(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OrderOfTheMirror.java b/Mage.Sets/src/mage/cards/o/OrderOfTheMirror.java index f76a36fd9d0..e5956a031da 100644 --- a/Mage.Sets/src/mage/cards/o/OrderOfTheMirror.java +++ b/Mage.Sets/src/mage/cards/o/OrderOfTheMirror.java @@ -1,12 +1,12 @@ package mage.cards.o; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.BecomesBlockedByCreatureTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,20 +15,25 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class OrderOfTheMirror extends CardImpl { +public final class OrderOfTheMirror extends TransformingDoubleFacedCard { public OrderOfTheMirror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "{1}{U}", + "Order of the Alabaster Host", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.KNIGHT}, "WU"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.o.OrderOfTheAlabasterHost.class; + // Order of the Mirror + this.getLeftHalfCard().setPT(2, 1); // {3}{W/P}: Transform Order of the Mirror. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{W/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{W/P}"))); + + // Order of the Alabaster Host + this.getRightHalfCard().setPT(3, 3); + + // Whenever Order of the Alabaster Host becomes blocked by a creature, that creature gets -1/-1 until end of turn. + this.getRightHalfCard().addAbility(new BecomesBlockedByCreatureTriggeredAbility(new BoostTargetEffect(-1, -1).setText("the blocking creature gets -1/-1 until end of turn"), false)); } private OrderOfTheMirror(final OrderOfTheMirror card) { diff --git a/Mage.Sets/src/mage/cards/o/OreRichStalactite.java b/Mage.Sets/src/mage/cards/o/OreRichStalactite.java index e0b5ea18204..7feb3ac803e 100644 --- a/Mage.Sets/src/mage/cards/o/OreRichStalactite.java +++ b/Mage.Sets/src/mage/cards/o/OreRichStalactite.java @@ -1,18 +1,32 @@ package mage.cards.o; -import java.util.UUID; - +import mage.MageObject; import mage.Mana; import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.mana.ConditionalColoredManaAbility; import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.cards.c.CosmiumCatalyst; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInExile; +import mage.util.CardUtil; + +import java.util.UUID; /** * Ore-Rich Stalactite {1}{R} @@ -22,20 +36,30 @@ import mage.filter.predicate.mageobject.ColorPredicate; * * @author DominionSpy */ -public class OreRichStalactite extends CardImpl { +public class OreRichStalactite extends TransformingDoubleFacedCard { public OreRichStalactite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}"); - this.secondSideCardClazz = CosmiumCatalyst.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{R}", + "Cosmium Catalyst", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "R" + ); + // Ore-Rich Stalactite // {T}: Add {R}. Spend this mana only to cast an instant or sorcery spell. - this.addAbility(new ConditionalColoredManaAbility(Mana.RedMana(1), new InstantOrSorcerySpellManaBuilder())); + this.getLeftHalfCard().addAbility(new ConditionalColoredManaAbility(Mana.RedMana(1), new InstantOrSorcerySpellManaBuilder())); // Craft with four or more red instant and/or sorcery cards {3}{R}{R} - this.addAbility(new CraftAbility("{3}{R}{R}", "four or more red instant and/or sorcery cards", + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{R}{R}", "four or more red instant and/or sorcery cards", "red instant and/or sorcery cards in your graveyard", 4, Integer.MAX_VALUE, new ColorPredicate(ObjectColor.RED), Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate()))); + + // Cosmium Catalyst + // {1}{R}, {T}: Choose an exiled card used to craft Cosmium Catalyst at random. You may cast that card without paying its mana cost. + Ability ability = new SimpleActivatedAbility(new CosmiumCatalystEffect(), new ManaCostsImpl<>("{1}{R}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); } private OreRichStalactite(final OreRichStalactite card) { @@ -43,7 +67,53 @@ public class OreRichStalactite extends CardImpl { } @Override - public OreRichStalactite copy() { + public OreRichStalactite copy() { return new OreRichStalactite(this); } } + +class CosmiumCatalystEffect extends OneShotEffect { + + CosmiumCatalystEffect() { + super(Outcome.PlayForFree); + this.staticText = "Choose an exiled card used to craft {this} at random." + + " You may cast that card without paying its mana cost."; + } + + private CosmiumCatalystEffect(CosmiumCatalystEffect effect) { + super(effect); + } + + @Override + public CosmiumCatalystEffect copy() { + return new CosmiumCatalystEffect(this); + } + + @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; + } + + Target target = new TargetCardInExile(StaticFilters.FILTER_CARD, + CardUtil.getExileZoneId(game, source.getSourceId(), + game.getState().getZoneChangeCounter(source.getSourceId()) - 2 + )); + target.withNotTarget(true); + target.setRandom(true); + if (!target.canChoose(controller.getId(), source, game)) { + return true; + } + target.chooseTarget(outcome, controller.getId(), source, game); + Card chosenCard = game.getCard(target.getFirstTarget()); + if (chosenCard != null) { + CardUtil.castSpellWithAttributesForFree(controller, source, game, chosenCard); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OriginOfMetalbending.java b/Mage.Sets/src/mage/cards/o/OriginOfMetalbending.java new file mode 100644 index 00000000000..9db58f9068a --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OriginOfMetalbending.java @@ -0,0 +1,49 @@ +package mage.cards.o; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +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.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OriginOfMetalbending extends CardImpl { + + public OriginOfMetalbending(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + this.subtype.add(SubType.LESSON); + + // Choose one -- + // * Destroy target artifact or enchantment. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + + // * Put a +1/+1 counter on target creature you control. It gains indestructible until end of turn. + this.getSpellAbility().addMode(new Mode(new AddCountersTargetEffect(CounterType.P1P1.createInstance())) + .addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()) + .setText("It gains indestructible until end of turn")) + .addTarget(new TargetControlledCreaturePermanent())); + } + + private OriginOfMetalbending(final OriginOfMetalbending card) { + super(card); + } + + @Override + public OriginOfMetalbending copy() { + return new OriginOfMetalbending(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrmendahlProfanePrince.java b/Mage.Sets/src/mage/cards/o/OrmendahlProfanePrince.java deleted file mode 100644 index 1df4cf81eeb..00000000000 --- a/Mage.Sets/src/mage/cards/o/OrmendahlProfanePrince.java +++ /dev/null @@ -1,51 +0,0 @@ - -package mage.cards.o; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.IndestructibleAbility; -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; - -/** - * - * @author fireshoes - */ -public final class OrmendahlProfanePrince extends CardImpl { - - public OrmendahlProfanePrince(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.power = new MageInt(9); - this.toughness = new MageInt(7); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - // Indestructible - this.addAbility(IndestructibleAbility.getInstance()); - // Haste - this.addAbility(HasteAbility.getInstance()); - } - - private OrmendahlProfanePrince(final OrmendahlProfanePrince card) { - super(card); - } - - @Override - public OrmendahlProfanePrince copy() { - return new OrmendahlProfanePrince(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OrmendahlTheCorrupter.java b/Mage.Sets/src/mage/cards/o/OrmendahlTheCorrupter.java deleted file mode 100644 index 146362a66fb..00000000000 --- a/Mage.Sets/src/mage/cards/o/OrmendahlTheCorrupter.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.FlyingAbility; -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 mage.constants.SuperType; -import mage.filter.StaticFilters; -import mage.target.common.TargetControlledPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class OrmendahlTheCorrupter extends CardImpl { - - public OrmendahlTheCorrupter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Sacrifice another creature: Draw a card. - this.addAbility(new SimpleActivatedAbility( - new DrawCardSourceControllerEffect(1), - new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) - )); - } - - private OrmendahlTheCorrupter(final OrmendahlTheCorrupter card) { - super(card); - } - - @Override - public OrmendahlTheCorrupter copy() { - return new OrmendahlTheCorrupter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OrneryGoblin.java b/Mage.Sets/src/mage/cards/o/OrneryGoblin.java index 5c78ad12729..418e73e97db 100644 --- a/Mage.Sets/src/mage/cards/o/OrneryGoblin.java +++ b/Mage.Sets/src/mage/cards/o/OrneryGoblin.java @@ -24,7 +24,7 @@ public final class OrneryGoblin extends CardImpl { this.toughness = new MageInt(1); // Whenever Ornery Goblin blocks or becomes blocked by a creature, Ornery Goblin deals 1 damage to that creature. - this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); + this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"))); } private OrneryGoblin(final OrneryGoblin card) { diff --git a/Mage.Sets/src/mage/cards/o/OscorpIndustries.java b/Mage.Sets/src/mage/cards/o/OscorpIndustries.java index f694701108b..d2bf00ac565 100644 --- a/Mage.Sets/src/mage/cards/o/OscorpIndustries.java +++ b/Mage.Sets/src/mage/cards/o/OscorpIndustries.java @@ -20,7 +20,7 @@ import java.util.UUID; public final class OscorpIndustries extends CardImpl { public OscorpIndustries(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); // This land enters tapped. @@ -35,7 +35,7 @@ public final class OscorpIndustries extends CardImpl { this.addAbility(new RedManaAbility()); // Mayhem - this.addAbility(new MayhemLandAbility(this)); + this.addAbility(new MayhemLandAbility()); } diff --git a/Mage.Sets/src/mage/cards/o/OstrichHorse.java b/Mage.Sets/src/mage/cards/o/OstrichHorse.java index 4c4131db6f5..5ed227bafca 100644 --- a/Mage.Sets/src/mage/cards/o/OstrichHorse.java +++ b/Mage.Sets/src/mage/cards/o/OstrichHorse.java @@ -29,7 +29,7 @@ public final class OstrichHorse extends CardImpl { // When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature. this.addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( 3, StaticFilters.FILTER_CARD_LAND, new AddCountersSourceEffect(CounterType.P1P1.createInstance()) - ))); + ).withTextOptions("them"))); } private OstrichHorse(final OstrichHorse card) { diff --git a/Mage.Sets/src/mage/cards/o/OteclanLandmark.java b/Mage.Sets/src/mage/cards/o/OteclanLandmark.java index 214752e856a..664238f4970 100644 --- a/Mage.Sets/src/mage/cards/o/OteclanLandmark.java +++ b/Mage.Sets/src/mage/cards/o/OteclanLandmark.java @@ -1,28 +1,60 @@ package mage.cards.o; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class OteclanLandmark extends CardImpl { +public final class OteclanLandmark extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterAttackingCreature("attacking creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } public OteclanLandmark(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{W}"); - this.secondSideCardClazz = mage.cards.o.OteclanLevitator.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{W}", + "Oteclan Levitator", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "W"); + + // Oteclan Landmark + this.getRightHalfCard().setPT(1, 4); // When Oteclan Landmark enters the battlefield, scry 2. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); // Craft with artifact {2}{W} - this.addAbility(new CraftAbility("{2}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{2}{W}")); + + // Oteclan Levitator + this.getRightHalfCard().setPT(1, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Oteclan Levitator attacks, target attacking creature without flying gains flying until end of turn. + Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); + ability.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(ability); } private OteclanLandmark(final OteclanLandmark card) { diff --git a/Mage.Sets/src/mage/cards/o/OteclanLevitator.java b/Mage.Sets/src/mage/cards/o/OteclanLevitator.java deleted file mode 100644 index d017143a0fa..00000000000 --- a/Mage.Sets/src/mage/cards/o/OteclanLevitator.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.o; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -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.FilterAttackingCreature; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class OteclanLevitator extends CardImpl { - - private static final FilterPermanent filter = new FilterAttackingCreature("attacking creature without flying"); - - static { - filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - } - - public OteclanLevitator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setWhite(true); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Oteclan Levitator attacks, target attacking creature without flying gains flying until end of turn. - Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - } - - private OteclanLevitator(final OteclanLevitator card) { - super(card); - } - - @Override - public OteclanLevitator copy() { - return new OteclanLevitator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OutlandLiberator.java b/Mage.Sets/src/mage/cards/o/OutlandLiberator.java index bed09388e24..ae9a21801a1 100644 --- a/Mage.Sets/src/mage/cards/o/OutlandLiberator.java +++ b/Mage.Sets/src/mage/cards/o/OutlandLiberator.java @@ -1,17 +1,21 @@ package mage.cards.o; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.target.TargetPermanent; import java.util.UUID; @@ -19,25 +23,49 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class OutlandLiberator extends CardImpl { +public final class OutlandLiberator extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter + = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment defending player controls"); + + static { + filter.add(DefendingPlayerControlsSourceAttackingPredicate.instance); + } public OutlandLiberator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}", + "Frenzied Trapbreaker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.f.FrenziedTrapbreaker.class; + // Outland Liberator + this.getLeftHalfCard().setPT(2, 2); // {1}, Sacrifice Outland Liberator: Destroy target artifact or enchantment. Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(1)); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Frenzied Trapbreaker + this.getRightHalfCard().setPT(3, 3); + + // {1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment. + ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new GenericManaCost(1)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.getRightHalfCard().addAbility(ability); + + // Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls. + ability = new AttacksTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(ability); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private OutlandLiberator(final OutlandLiberator card) { diff --git a/Mage.Sets/src/mage/cards/o/Overabundance.java b/Mage.Sets/src/mage/cards/o/Overabundance.java index 94b7b809584..ea68ec6f634 100644 --- a/Mage.Sets/src/mage/cards/o/Overabundance.java +++ b/Mage.Sets/src/mage/cards/o/Overabundance.java @@ -30,7 +30,7 @@ public final class Overabundance extends CardImpl { )); this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), new FilterLandPermanent("a player taps a land"), SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/o/OverloadedMageRing.java b/Mage.Sets/src/mage/cards/o/OverloadedMageRing.java deleted file mode 100644 index 65100d111e6..00000000000 --- a/Mage.Sets/src/mage/cards/o/OverloadedMageRing.java +++ /dev/null @@ -1,53 +0,0 @@ -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.CopyTargetStackObjectEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TargetController; -import mage.filter.FilterSpell; -import mage.target.TargetSpell; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class OverloadedMageRing extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("spell you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - - public OverloadedMageRing(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.color.setBlue(true); - this.nightCard = true; - - // {1}, {T}, Sacrifice Overloaded Mage-Ring: Copy target spell you control. You may choose new targets for the copy. - Ability ability = new SimpleActivatedAbility( - new CopyTargetStackObjectEffect(false, false, true), new GenericManaCost(1) - ); - ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetSpell(filter)); - this.addAbility(ability); - } - - private OverloadedMageRing(final OverloadedMageRing card) { - super(card); - } - - @Override - public OverloadedMageRing copy() { - return new OverloadedMageRing(this); - } -} diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java b/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java index 22e968cb057..38d597fa611 100644 --- a/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java +++ b/Mage.Sets/src/mage/cards/o/OverwhelmedArchivist.java @@ -1,12 +1,12 @@ package mage.cards.o; -import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.keyword.DisturbAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,22 +15,34 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class OverwhelmedArchivist extends CardImpl { +public final class OverwhelmedArchivist extends TransformingDoubleFacedCard { public OverwhelmedArchivist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{2}{U}", + "Archive Haunt", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WIZARD}, "U"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.a.ArchiveHaunt.class; + // Overwhelmed Archivist + this.getLeftHalfCard().setPT(3, 2); // When Overwhelmed Archivist enters the battlefield, draw a card, then discard a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); // Disturb {3}{U} - this.addAbility(new DisturbAbility(this, "{3}{U}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{3}{U}")); + + // Archive Haunt + this.getRightHalfCard().setPT(2, 1); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Archive Haunt attacks, draw a card, then discard a card. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DrawDiscardControllerEffect(1, 1))); + + // If Archive Haunt would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private OverwhelmedArchivist(final OverwhelmedArchivist card) { diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmingVictory.java b/Mage.Sets/src/mage/cards/o/OverwhelmingVictory.java new file mode 100644 index 00000000000..7b939370502 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OverwhelmingVictory.java @@ -0,0 +1,79 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +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.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OverwhelmingVictory extends CardImpl { + + public OverwhelmingVictory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + this.subtype.add(SubType.LESSON); + + // Overwhelming Victory deals 5 damage to target creature. Each creature you control gains trample and gets +X/+0 until end of turn, where X is the amount of excess damage dealt this way. + this.getSpellAbility().addEffect(new OverwhelmingVictoryEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private OverwhelmingVictory(final OverwhelmingVictory card) { + super(card); + } + + @Override + public OverwhelmingVictory copy() { + return new OverwhelmingVictory(this); + } +} + +class OverwhelmingVictoryEffect extends OneShotEffect { + + OverwhelmingVictoryEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 5 damage to target creature. Each creature you control gains trample " + + "and gets +X/+0 until end of turn, where X is the amount of excess damage dealt this way"; + } + + private OverwhelmingVictoryEffect(final OverwhelmingVictoryEffect effect) { + super(effect); + } + + @Override + public OverwhelmingVictoryEffect copy() { + return new OverwhelmingVictoryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int excess = Optional + .ofNullable(getTargetPointer().getFirst(game, source)) + .map(game::getPermanent) + .map(permanent -> permanent.damageWithExcess(5, source, game)) + .orElse(0); + game.addEffect(new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ), source); + if (excess > 0) { + game.addEffect(new BoostControlledEffect(excess, 0, Duration.EndOfTurn), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OzaiThePhoenixKing.java b/Mage.Sets/src/mage/cards/o/OzaiThePhoenixKing.java new file mode 100644 index 00000000000..4ef9e353d15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OzaiThePhoenixKing.java @@ -0,0 +1,123 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.*; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.ManaPool; +import mage.players.Player; + +/** + * + * @author anonymous + */ +public final class OzaiThePhoenixKing extends CardImpl { + + public OzaiThePhoenixKing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Firebending 4 + this.addAbility(new FirebendingAbility(4)); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // If you would lose unspent mana, that mana becomes red instead. + this.addAbility(new SimpleStaticAbility(new OzaiThePhoenixKingManaEffect())); + + // Ozai has flying and indestructible as long as you have six or more unspent mana. + this.addAbility(new SimpleStaticAbility(new OzaiThePhoenixKingBoostEffect())); + } + + private OzaiThePhoenixKing(final OzaiThePhoenixKing card) { + super(card); + } + + @Override + public OzaiThePhoenixKing copy() { + return new OzaiThePhoenixKing(this); + } +} + +class OzaiThePhoenixKingManaEffect extends ContinuousEffectImpl { + + OzaiThePhoenixKingManaEffect() { + super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit); + staticText = "if you would lose unspent mana, that mana becomes red instead"; + } + + private OzaiThePhoenixKingManaEffect(final OzaiThePhoenixKingManaEffect effect) { + super(effect); + } + + @Override + public OzaiThePhoenixKingManaEffect copy() { + return new OzaiThePhoenixKingManaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.getManaPool().setManaBecomesRed(true); + } + return true; + } +} + +class OzaiThePhoenixKingBoostEffect extends ContinuousEffectImpl { + + OzaiThePhoenixKingBoostEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "{this} has flying and indestructible as long as you have six or more unspent mana"; + } + + private OzaiThePhoenixKingBoostEffect(final OzaiThePhoenixKingBoostEffect effect) { + super(effect); + } + + @Override + public OzaiThePhoenixKingBoostEffect copy() { + return new OzaiThePhoenixKingBoostEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent creature = game.getPermanent(source.getSourceId()); + if (controller == null || creature == null) { + return false; + } + ManaPool pool = controller.getManaPool(); + int blackMana = pool.getBlack(); + int whiteMana = pool.getWhite(); + int blueMana = pool.getBlue(); + int greenMana = pool.getGreen(); + int redMana = pool.getRed(); + int colorlessMana = pool.getColorless(); + int manaPoolTotal = blackMana + whiteMana + blueMana + greenMana + redMana + colorlessMana; + if (manaPoolTotal >= 6) { + creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + creature.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game); + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PaintersServant.java b/Mage.Sets/src/mage/cards/p/PaintersServant.java index bdffc476a83..4c47d77655f 100644 --- a/Mage.Sets/src/mage/cards/p/PaintersServant.java +++ b/Mage.Sets/src/mage/cards/p/PaintersServant.java @@ -107,10 +107,10 @@ class PaintersServantEffect extends ContinuousEffectImpl { affectedCards.forEach(card -> { game.getState().getCreateMageObjectAttribute(card, game).getColor().addColor(color); - // mdf cards - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + // df cards + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().addColor(color); game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().addColor(color); } @@ -124,6 +124,7 @@ class PaintersServantEffect extends ContinuousEffectImpl { } // double faces cards + // TODO: can remove after tdfc rework if (card.getSecondCardFace() != null) { game.getState().getCreateMageObjectAttribute(card.getSecondCardFace(), game).getColor().addColor(color); } diff --git a/Mage.Sets/src/mage/cards/p/PaintersStudioDefacedGallery.java b/Mage.Sets/src/mage/cards/p/PaintersStudioDefacedGallery.java new file mode 100644 index 00000000000..b85b90b3296 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PaintersStudioDefacedGallery.java @@ -0,0 +1,43 @@ +package mage.cards.p; + +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PaintersStudioDefacedGallery extends RoomCard { + + public PaintersStudioDefacedGallery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{R}", "{1}{R}"); + + // Painter's Studio + // When you unlock this door, exile the top two cards of your library. You may play them until the end of your next turn. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility( + new ExileTopXMayPlayUntilEffect(2, Duration.UntilEndOfYourNextTurn), false, true + )); + + // Defaced Gallery + // Whenever you attack, attacking creatures you control get +1/+0 until end of turn. + this.getRightHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new BoostControlledEffect( + 1, 0, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES + ), 1)); + } + + private PaintersStudioDefacedGallery(final PaintersStudioDefacedGallery card) { + super(card); + } + + @Override + public PaintersStudioDefacedGallery copy() { + return new PaintersStudioDefacedGallery(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PanickedBystander.java b/Mage.Sets/src/mage/cards/p/PanickedBystander.java index fc914a322bb..ddbd9211755 100644 --- a/Mage.Sets/src/mage/cards/p/PanickedBystander.java +++ b/Mage.Sets/src/mage/cards/p/PanickedBystander.java @@ -1,20 +1,20 @@ package mage.cards.p; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.watchers.common.PlayerGainedLifeWatcher; @@ -23,30 +23,45 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class PanickedBystander extends CardImpl { +public final class PanickedBystander extends TransformingDoubleFacedCard { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); public PanickedBystander(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{W}", + "Cackling Culprit", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.c.CacklingCulprit.class; + // Panicked Bystander + this.getLeftHalfCard().setPT(2, 2); // Whenever Panicked Bystander or another creature you control dies, you gain 1 life. - this.addAbility(new DiesThisOrAnotherTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( new GainLifeEffect(1), false, StaticFilters.FILTER_CONTROLLED_CREATURE )); // At the beginning of your end step, if you gained 3 or more life this turn, transform Panicked Bystander. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( + Ability ability = new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new TransformSourceEffect(), false, condition - ).addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); + ).addHint(ControllerGainedLifeCount.getHint()); + ability.addWatcher(new PlayerGainedLifeWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Cackling Culprit + this.getRightHalfCard().setPT(3, 5); + + // Whenever Cackling Culprit or another creature you control dies, you gain 1 life. + this.getRightHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( + new GainLifeEffect(1), false, StaticFilters.FILTER_CONTROLLED_CREATURE + )); + + // {1}{B}: Cackling Culprit gains deathtouch until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{1}{B}"))); } private PanickedBystander(final PanickedBystander card) { diff --git a/Mage.Sets/src/mage/cards/p/PathOfMettle.java b/Mage.Sets/src/mage/cards/p/PathOfMettle.java index df91c7112e3..d1b90ba4071 100644 --- a/Mage.Sets/src/mage/cards/p/PathOfMettle.java +++ b/Mage.Sets/src/mage/cards/p/PathOfMettle.java @@ -1,28 +1,39 @@ package mage.cards.p; -import java.util.UUID; - +import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; 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.util.RandomUtil; +import mage.watchers.common.AttackedThisTurnWatcher; + +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 */ -public final class PathOfMettle extends CardImpl { +public final class PathOfMettle extends TransformingDoubleFacedCard { private static final FilterCreaturePermanent filterDamage = new FilterCreaturePermanent("creature that doesn't have first strike, double strike, vigilance, or haste"); private static final FilterCreaturePermanent filterTransform = new FilterCreaturePermanent("creatures that have first strike, double strike, vigilance, and/or haste"); @@ -45,18 +56,32 @@ public final class PathOfMettle extends CardImpl { } public PathOfMettle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}"); - - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.m.MetzaliTowerOfTriumph.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{R}{W}", + "Metzali, Tower of Triumph", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Path of Mettle // When Path of Mettle enters the battlefield, it deals 1 damage to each creature that doesn't have first strike, double strike, vigilance, or haste. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DamageAllEffect(1, "it", filterDamage))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DamageAllEffect(1, "it", filterDamage))); // Whenever you attack with at least two creatures that have first strike, double strike, vigilance, and/or haste, transform Path of Mettle. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksWithCreaturesTriggeredAbility(new TransformSourceEffect(), 2, filterTransform).setTriggerPhrase(triggerPhrase)); + this.getLeftHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new TransformSourceEffect(), 2, filterTransform).setTriggerPhrase(triggerPhrase)); + + // Metzali, Tower of Triumph + // {t}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); + + // {1}{R}, {T}: Metzali, Tower of Triumph deals 2 damage to each opponent. + Ability ability = new SimpleActivatedAbility(new DamagePlayersEffect(2, TargetController.OPPONENT), new ManaCostsImpl<>("{1}{R}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); + + // {2}{W}, {T}: Choose a creature at random that attacked this turn. Destroy that creature. + ability = new SimpleActivatedAbility(new MetzaliTowerOfTriumphDestroyEffect(), new ManaCostsImpl<>("{2}{W}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); } private PathOfMettle(final PathOfMettle card) { @@ -68,3 +93,34 @@ public final class PathOfMettle extends CardImpl { return new PathOfMettle(this); } } + +class MetzaliTowerOfTriumphDestroyEffect extends OneShotEffect { + + MetzaliTowerOfTriumphDestroyEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "choose a creature at random that attacked this turn. Destroy that creature"; + } + + private MetzaliTowerOfTriumphDestroyEffect(final MetzaliTowerOfTriumphDestroyEffect effect) { + super(effect); + } + + @Override + public MetzaliTowerOfTriumphDestroyEffect copy() { + return new MetzaliTowerOfTriumphDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = RandomUtil.randomFromCollection( + game.getState() + .getWatcher(AttackedThisTurnWatcher.class) + .getAttackedThisTurnCreatures() + .stream() + .map(mor -> mor.getPermanent(game)) + .filter(Objects::nonNull) + .collect(Collectors.toSet()) + ); + return permanent != null && permanent.destroy(source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PaupersCage.java b/Mage.Sets/src/mage/cards/p/PaupersCage.java index 2c976f03dca..757ffb2fbea 100644 --- a/Mage.Sets/src/mage/cards/p/PaupersCage.java +++ b/Mage.Sets/src/mage/cards/p/PaupersCage.java @@ -24,7 +24,7 @@ public final class PaupersCage extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Paupers' Cage deals 2 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.OPPONENT, new DamageTargetEffect(2, true, "that player"), false + TargetController.OPPONENT, new DamageTargetEffect(2).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/p/PerfectIntimidation.java b/Mage.Sets/src/mage/cards/p/PerfectIntimidation.java new file mode 100644 index 00000000000..6095f5afecf --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PerfectIntimidation.java @@ -0,0 +1,44 @@ +package mage.cards.p; + +import mage.abilities.Mode; +import mage.abilities.effects.common.ExileFromZoneTargetEffect; +import mage.abilities.effects.common.counter.RemoveAllCountersPermanentTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PerfectIntimidation extends CardImpl { + + public PerfectIntimidation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Choose one or both -- + // * Target opponent exiles two cards from their hand. + this.getSpellAbility().addEffect(new ExileFromZoneTargetEffect( + Zone.HAND, StaticFilters.FILTER_CARD_CARDS, 2, false + )); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // * Remove all counters from target creature. + this.getSpellAbility().addMode(new Mode(new RemoveAllCountersPermanentTargetEffect()) + .addTarget(new TargetCreaturePermanent())); + } + + private PerfectIntimidation(final PerfectIntimidation card) { + super(card); + } + + @Override + public PerfectIntimidation copy() { + return new PerfectIntimidation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PerfectedForm.java b/Mage.Sets/src/mage/cards/p/PerfectedForm.java deleted file mode 100644 index 64232ed2ee7..00000000000 --- a/Mage.Sets/src/mage/cards/p/PerfectedForm.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.p; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class PerfectedForm extends CardImpl { - - public PerfectedForm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.INSECT); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private PerfectedForm(final PerfectedForm card) { - super(card); - } - - @Override - public PerfectedForm copy() { - return new PerfectedForm(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PersistentNightmare.java b/Mage.Sets/src/mage/cards/p/PersistentNightmare.java deleted file mode 100644 index d1825f3f44b..00000000000 --- a/Mage.Sets/src/mage/cards/p/PersistentNightmare.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandSourceEffect; -import mage.abilities.keyword.SkulkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class PersistentNightmare extends CardImpl { - - public PersistentNightmare(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.NIGHTMARE); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Skulk - this.addAbility(new SkulkAbility()); - - // When Persistent Nightmare deals combat damage to a player, return it to its owner's hand. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new ReturnToHandSourceEffect(), false - ).setTriggerPhrase("When {this} deals combat damage to a player, ")); - } - - private PersistentNightmare(final PersistentNightmare card) { - super(card); - } - - @Override - public PersistentNightmare copy() { - return new PersistentNightmare(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PersonalSanctuary.java b/Mage.Sets/src/mage/cards/p/PersonalSanctuary.java index 6dc513854e7..2798dd1edfa 100644 --- a/Mage.Sets/src/mage/cards/p/PersonalSanctuary.java +++ b/Mage.Sets/src/mage/cards/p/PersonalSanctuary.java @@ -7,12 +7,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import java.util.UUID; @@ -50,18 +46,6 @@ class PersonalSanctuaryEffect extends PreventionEffectImpl { super(effect); } - @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 damage = event.getAmount(); - event.setAmount(0); - game.informPlayers("Damage has been prevented: " + damage); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER) { diff --git a/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java b/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java new file mode 100644 index 00000000000..7c6ca6aea08 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhoenixFleetAirship.java @@ -0,0 +1,96 @@ +package mage.cards.p; + +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.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; +import mage.abilities.effects.CreateTokenCopySourceEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +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.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.watchers.common.PermanentsSacrificedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PhoenixFleetAirship extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new NamePredicate("Phoenix Fleet Airship")); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 7); + private static final Hint hint = new ValueHint( + "Permanents you control named Phoenix Fleet Airship", new PermanentsOnBattlefieldCount(filter) + ); + + public PhoenixFleetAirship(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}{B}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your end step, if you sacrificed a permanent this turn, create a token that's a copy of this Vehicle. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenCopySourceEffect()) + .withInterveningIf(PhoenixFleetAirshipCondition.instance) + .addHint(PermanentsSacrificedThisTurnCount.YOU.getHint()), new PermanentsSacrificedWatcher()); + + // As long as you control eight or more permanents named Phoenix Fleet Airship, this Vehicle is an artifact creature. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new AddCardTypeSourceEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT, CardType.CREATURE), + condition, "as long as you control eight or more permanents " + + "named Phoenix Fleet Airship, this Vehicle is an artifact creature" + )).addHint(hint)); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private PhoenixFleetAirship(final PhoenixFleetAirship card) { + super(card); + } + + @Override + public PhoenixFleetAirship copy() { + return new PhoenixFleetAirship(this); + } +} + +enum PhoenixFleetAirshipCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return PermanentsSacrificedThisTurnCount.YOU.calculate(game, source, null) > 0; + } + + @Override + public String toString() { + return "you sacrificed a permanent this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhoenixWardenOfFire.java b/Mage.Sets/src/mage/cards/p/PhoenixWardenOfFire.java deleted file mode 100644 index 9a9ff1da417..00000000000 --- a/Mage.Sets/src/mage/cards/p/PhoenixWardenOfFire.java +++ /dev/null @@ -1,125 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.target.common.TargetCardInYourGraveyard; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PhoenixWardenOfFire extends CardImpl { - - public PhoenixWardenOfFire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.PHOENIX); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setRed(true); - this.color.setWhite(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Rising Flames -- Phoenix deals 2 damage to each opponent. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { - ability.addEffect(new DamagePlayersEffect(2, TargetController.OPPONENT)); - ability.withFlavorWord("Rising Flames"); - }); - - // III -- Flames of Rebirth -- Return any number of target creature cards with total mana value 6 or less from your graveyard to the battlefield. Exile Phoenix, then return it to the battlefield. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - ability.addEffect(new ExileSourceAndReturnFaceUpEffect()); - ability.addTarget(new PhoenixWardenOfFireTarget()); - ability.withFlavorWord("Flames of Rebirth"); - }); - this.addAbility(sagaAbility); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private PhoenixWardenOfFire(final PhoenixWardenOfFire card) { - super(card); - } - - @Override - public PhoenixWardenOfFire copy() { - return new PhoenixWardenOfFire(this); - } -} - -class PhoenixWardenOfFireTarget extends TargetCardInYourGraveyard { - - private static final FilterCard filterStatic = new FilterCreatureCard( - "creature cards with total mana value 6 or less from your graveyard" - ); - - PhoenixWardenOfFireTarget() { - super(0, Integer.MAX_VALUE, filterStatic, false); - } - - private PhoenixWardenOfFireTarget(final PhoenixWardenOfFireTarget target) { - super(target); - } - - @Override - public PhoenixWardenOfFireTarget copy() { - return new PhoenixWardenOfFireTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - return super.canTarget(playerId, id, source, game) - && CardUtil.checkCanTargetTotalValueLimit( - this.getTargets(), id, MageObject::getManaValue, 6, game - ); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - return CardUtil.checkPossibleTargetsTotalValueLimit( - this.getTargets(), - super.possibleTargets(sourceControllerId, source, game), - MageObject::getManaValue, 6, game - ); - } - - @Override - public String getMessage(Game game) { - // shows selected total - int selectedValue = this - .getTargets() - .stream() - .map(game::getObject) - .filter(Objects::nonNull) - .mapToInt(MageObject::getManaValue) - .sum(); - return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java index e5007931682..7b1ca32472f 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java @@ -3,6 +3,7 @@ package mage.cards.p; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.keyword.InfectAbility; import mage.cards.CardImpl; @@ -10,13 +11,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import java.util.UUID; @@ -67,19 +64,15 @@ class PhyrexianHydraEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - boolean retValue = false; - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - int damage = event.getAmount(); - if (!game.replaceEvent(preventEvent)) { - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - retValue = true; + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.addCounters(CounterType.M1M1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); + } + return false; } - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.addCounters(CounterType.M1M1.createInstance(damage), source.getControllerId(), source, game); - } - return retValue; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSkyflayer.java b/Mage.Sets/src/mage/cards/p/PhyrexianSkyflayer.java deleted file mode 100644 index 765afc12b0d..00000000000 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSkyflayer.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -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 PhyrexianSkyflayer extends CardImpl { - - public PhyrexianSkyflayer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ARTIFICER); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.color.setRed(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - } - - private PhyrexianSkyflayer(final PhyrexianSkyflayer card) { - super(card); - } - - @Override - public PhyrexianSkyflayer copy() { - return new PhyrexianSkyflayer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java b/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java index ab81e6a79d4..83e9d3ed0b4 100644 --- a/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java +++ b/Mage.Sets/src/mage/cards/p/PinpointAvalanche.java @@ -18,7 +18,7 @@ public final class PinpointAvalanche extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}{R}"); // Pinpoint Avalanche deals 4 damage to target creature. The damage can't be prevented. - this.getSpellAbility().addEffect(new DamageTargetEffect(4, false)); + this.getSpellAbility().addEffect(new DamageTargetEffect(4).withCantBePrevented()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/p/PiousEvangel.java b/Mage.Sets/src/mage/cards/p/PiousEvangel.java index 1de94395713..54abaf03580 100644 --- a/Mage.Sets/src/mage/cards/p/PiousEvangel.java +++ b/Mage.Sets/src/mage/cards/p/PiousEvangel.java @@ -1,57 +1,69 @@ package mage.cards.p; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; import java.util.UUID; /** * @author fireshoes */ -public final class PiousEvangel extends CardImpl { +public final class PiousEvangel extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("another permanent"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); static { filter2.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getControllerPredicate()); } public PiousEvangel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{2}{W}", + "Wayward Disciple", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "B" + ); - this.secondSideCardClazz = mage.cards.w.WaywardDisciple.class; + // Pious Evangel + this.getLeftHalfCard().setPT(2, 2); // Whenever Pious Evangel or another creature you control enters, you gain 1 life. - this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(new GainLifeEffect(1), + this.getLeftHalfCard().addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(new GainLifeEffect(1), StaticFilters.FILTER_PERMANENT_CREATURE, false, true)); // {2}, {T}, Sacrifice another permanent: Transform Pious Evangel. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(filter2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Wayward Disciple + this.getRightHalfCard().setPT(2, 4); + + // Whenever Wayward Disciple or another creature you control dies, target opponent loses 1 life and you gain 1 life. + Ability abilityBack = new DiesThisOrAnotherTriggeredAbility(new LoseLifeTargetEffect(1), false, filter); + abilityBack.addEffect(new GainLifeEffect(1).concatBy("and")); + abilityBack.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(abilityBack); } private PiousEvangel(final PiousEvangel card) { diff --git a/Mage.Sets/src/mage/cards/p/PipsqueakRebelStrongarm.java b/Mage.Sets/src/mage/cards/p/PipsqueakRebelStrongarm.java new file mode 100644 index 00000000000..7280cbee6ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PipsqueakRebelStrongarm.java @@ -0,0 +1,51 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PipsqueakRebelStrongarm extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1, ComparisonType.EQUAL_TO, 0); + + public PipsqueakRebelStrongarm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Pipsqueak can't attack alone unless he has a +1/+1 counter on him. + this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantAttackAloneSourceEffect(), condition, + "{this} can't attack alone unless he has a +1/+1 counter on him" + ))); + } + + private PipsqueakRebelStrongarm(final PipsqueakRebelStrongarm card) { + super(card); + } + + @Override + public PipsqueakRebelStrongarm copy() { + return new PipsqueakRebelStrongarm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PiratePeddlers.java b/Mage.Sets/src/mage/cards/p/PiratePeddlers.java new file mode 100644 index 00000000000..1eff54a0024 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiratePeddlers.java @@ -0,0 +1,46 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PiratePeddlers extends CardImpl { + + public PiratePeddlers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever you sacrifice another permanent, put a +1/+1 counter on this creature. + this.addAbility(new SacrificePermanentTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT + )); + } + + private PiratePeddlers(final PiratePeddlers card) { + super(card); + } + + @Override + public PiratePeddlers copy() { + return new PiratePeddlers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlanetariumOfWanShiTong.java b/Mage.Sets/src/mage/cards/p/PlanetariumOfWanShiTong.java new file mode 100644 index 00000000000..0c6c9d526fe --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlanetariumOfWanShiTong.java @@ -0,0 +1,122 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +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.keyword.ScryEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.Zone; +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 PlanetariumOfWanShiTong extends CardImpl { + + public PlanetariumOfWanShiTong(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); + + this.supertype.add(SuperType.LEGENDARY); + + // {1}, {T}: Scry 2. + Ability ability = new SimpleActivatedAbility(new ScryEffect(2), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // Whenever you scry or surveil, look at the top card of your library. You may cast that card without paying its mana cost. Do this only once each turn. + this.addAbility(new PlanetariumOfWanShiTongTriggeredAbility()); + } + + private PlanetariumOfWanShiTong(final PlanetariumOfWanShiTong card) { + super(card); + } + + @Override + public PlanetariumOfWanShiTong copy() { + return new PlanetariumOfWanShiTong(this); + } +} + +class PlanetariumOfWanShiTongTriggeredAbility extends TriggeredAbilityImpl { + + PlanetariumOfWanShiTongTriggeredAbility() { + super(Zone.BATTLEFIELD, new PlanetariumOfWanShiTongEffect()); + this.setTriggerPhrase("Whenever you scry or surveil, "); + this.setDoOnlyOnceEachTurn(true); + this.setOptional(false); + } + + private PlanetariumOfWanShiTongTriggeredAbility(final PlanetariumOfWanShiTongTriggeredAbility ability) { + super(ability); + } + + @Override + public PlanetariumOfWanShiTongTriggeredAbility copy() { + return new PlanetariumOfWanShiTongTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + switch (event.getType()) { + case SCRIED: + case SURVEILED: + return true; + default: + return false; + } + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return isControlledBy(event.getPlayerId()); + } +} + +class PlanetariumOfWanShiTongEffect extends OneShotEffect { + + PlanetariumOfWanShiTongEffect() { + super(Outcome.Benefit); + staticText = "look at the top card of your library. You may cast that card without paying its mana cost"; + } + + private PlanetariumOfWanShiTongEffect(final PlanetariumOfWanShiTongEffect effect) { + super(effect); + } + + @Override + public PlanetariumOfWanShiTongEffect copy() { + return new PlanetariumOfWanShiTongEffect(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 library", card, game); + if (!CardUtil.castSpellWithAttributesForFree(player, source, game, card)) { + return false; + } + TriggeredAbility.setDidThisTurn(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlanetaryAnnihilation.java b/Mage.Sets/src/mage/cards/p/PlanetaryAnnihilation.java index 20b327efd38..cf140ece939 100644 --- a/Mage.Sets/src/mage/cards/p/PlanetaryAnnihilation.java +++ b/Mage.Sets/src/mage/cards/p/PlanetaryAnnihilation.java @@ -66,6 +66,7 @@ class PlanetaryAnnihilationEffect extends OneShotEffect { if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, playerId, source, game ) <= 6) { + toSave.addAll(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, playerId, game)); continue; } TargetPermanent target = new TargetPermanent( diff --git a/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java b/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java deleted file mode 100644 index f0cd80d8980..00000000000 --- a/Mage.Sets/src/mage/cards/p/PlatedKilnbeast.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -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 PlatedKilnbeast extends CardImpl { - - public PlatedKilnbeast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(7); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - } - - private PlatedKilnbeast(final PlatedKilnbeast card) { - super(card); - } - - @Override - public PlatedKilnbeast copy() { - return new PlatedKilnbeast(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PlatypusBear.java b/Mage.Sets/src/mage/cards/p/PlatypusBear.java new file mode 100644 index 00000000000..c7179e3c93b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlatypusBear.java @@ -0,0 +1,53 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.keyword.DefenderAbility; +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 PlatypusBear extends CardImpl { + + public PlatypusBear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G/U}"); + + this.subtype.add(SubType.PLATYPUS); + this.subtype.add(SubType.BEAR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // When this creature enters, mill two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); + + // As long as there is a Lesson card in your graveyard, this creature can attack as though it didn't have defender. + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), LessonsInGraveCondition.ONE + ).setText("as long as there is a Lesson card in your graveyard, " + + "this creature can attack as though it didn't have defender")).addHint(LessonsInGraveCondition.getHint())); + } + + private PlatypusBear(final PlatypusBear card) { + super(card); + } + + @Override + public PlatypusBear copy() { + return new PlatypusBear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PolukranosEngineOfRuin.java b/Mage.Sets/src/mage/cards/p/PolukranosEngineOfRuin.java deleted file mode 100644 index a1489a1f9cf..00000000000 --- a/Mage.Sets/src/mage/cards/p/PolukranosEngineOfRuin.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.ReachAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.permanent.token.PhyrexianHydraWithLifelinkToken; -import mage.game.permanent.token.PhyrexianHydraWithReachToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PolukranosEngineOfRuin extends CardImpl { - - private static final FilterPermanent filter - = new FilterControlledPermanent(SubType.HYDRA, "nontoken Hydra you control"); - - static { - filter.add(TokenPredicate.FALSE); - } - - public PolukranosEngineOfRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.HYDRA); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setWhite(true); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Whenever Polukranos, Engine of Ruin or another nontoken Hydra you control dies, create a 3/3 green and white Phyrexian Hydra creature token with reach and a 3/3 green and white Phyrexian Hydra creature token with lifelink. - this.addAbility(new DiesThisOrAnotherTriggeredAbility( - new CreateTokenEffect(new PhyrexianHydraWithReachToken()).withAdditionalTokens(new PhyrexianHydraWithLifelinkToken()), false, filter - )); - } - - private PolukranosEngineOfRuin(final PolukranosEngineOfRuin card) { - super(card); - } - - @Override - public PolukranosEngineOfRuin copy() { - return new PolukranosEngineOfRuin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PolukranosReborn.java b/Mage.Sets/src/mage/cards/p/PolukranosReborn.java index 5b28e453528..41de09e41e7 100644 --- a/Mage.Sets/src/mage/cards/p/PolukranosReborn.java +++ b/Mage.Sets/src/mage/cards/p/PolukranosReborn.java @@ -1,39 +1,65 @@ package mage.cards.p; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.ReachAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.PhyrexianHydraWithLifelinkToken; +import mage.game.permanent.token.PhyrexianHydraWithReachToken; import java.util.UUID; /** * @author TheElk801 */ -public final class PolukranosReborn extends CardImpl { +public final class PolukranosReborn extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.HYDRA, "nontoken Hydra you control"); + + static { + filter.add(TokenPredicate.FALSE); + } public PolukranosReborn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HYDRA}, "{G}{G}{G}", + "Polukranos, Engine of Ruin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.HYDRA}, "GW"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HYDRA); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.p.PolukranosEngineOfRuin.class; + // Polukranos Reborn + this.getLeftHalfCard().setPT(4, 5); // Reach - this.addAbility(ReachAbility.getInstance()); + this.getLeftHalfCard().addAbility(ReachAbility.getInstance()); // {6}{W/P}: Transform Polukranos Reborn. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{W/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{W/P}"))); + + // Polukranos, Engine of Ruin + this.getRightHalfCard().setPT(6, 6); + + // Reach + this.getRightHalfCard().addAbility(ReachAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Whenever Polukranos, Engine of Ruin or another nontoken Hydra you control dies, create a 3/3 green and white Phyrexian Hydra creature token with reach and a 3/3 green and white Phyrexian Hydra creature token with lifelink. + this.getRightHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( + new CreateTokenEffect(new PhyrexianHydraWithReachToken()).withAdditionalTokens(new PhyrexianHydraWithLifelinkToken()), false, filter + )); } private PolukranosReborn(final PolukranosReborn card) { diff --git a/Mage.Sets/src/mage/cards/p/PoppetFactory.java b/Mage.Sets/src/mage/cards/p/PoppetFactory.java deleted file mode 100644 index 6f43a33be51..00000000000 --- a/Mage.Sets/src/mage/cards/p/PoppetFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -package mage.cards.p; - -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PoppetFactory extends CardImpl { - - public PoppetFactory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.color.setBlue(true); - this.nightCard = true; - - // Creature tokens you control lose all abilities and have base power and toughness 3/3. - this.addAbility(new SimpleStaticAbility(new PoppetFactoryEffect())); - - // At the beginning of your upkeep, you may transform Poppet Factory. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new TransformSourceEffect(), true - )); - } - - private PoppetFactory(final PoppetFactory card) { - super(card); - } - - @Override - public PoppetFactory copy() { - return new PoppetFactory(this); - } -} - -class PoppetFactoryEffect extends ContinuousEffectImpl { - - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); - - static { - filter.add(TokenPredicate.TRUE); - } - - PoppetFactoryEffect() { - super(Duration.WhileOnBattlefield, Outcome.LoseAbility); - staticText = "creature tokens you control lose all abilities and have base power and toughness 3/3"; - } - - private PoppetFactoryEffect(final PoppetFactoryEffect effect) { - super(effect); - } - - @Override - public PoppetFactoryEffect copy() { - return new PoppetFactoryEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source, game - )) { - switch (layer) { - case AbilityAddingRemovingEffects_6: - permanent.removeAllAbilities(source.getSourceId(), game); - break; - case PTChangingEffects_7: - if (sublayer == SubLayer.SetPT_7b) { - permanent.getPower().setModifiedBaseValue(3); - permanent.getToughness().setModifiedBaseValue(3); - } - break; - } - } - 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/p/PoppetStitcher.java b/Mage.Sets/src/mage/cards/p/PoppetStitcher.java index 00b952d09a7..5fc530c84bf 100644 --- a/Mage.Sets/src/mage/cards/p/PoppetStitcher.java +++ b/Mage.Sets/src/mage/cards/p/PoppetStitcher.java @@ -1,25 +1,27 @@ package mage.cards.p; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieDecayedToken; import java.util.UUID; @@ -27,7 +29,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class PoppetStitcher extends CardImpl { +public final class PoppetStitcher extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more creature tokens"); @@ -41,25 +43,32 @@ public final class PoppetStitcher extends CardImpl { ); public PoppetStitcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{2}{U}", + "Poppet Factory", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.p.PoppetFactory.class; + // Poppet Stitcher + this.getLeftHalfCard().setPT(2, 3); // Whenever you cast an instant or sorcery spell, create a 2/2 black Zombie creature token with decayed. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( new CreateTokenEffect(new ZombieDecayedToken()), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false )); // At the beginning of your upkeep, if you control three or more creature tokens, you may transform Poppet Sticher. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true) + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true) .withInterveningIf(condition).addHint(hint)); + + // Poppet Factory + // Creature tokens you control lose all abilities and have base power and toughness 3/3. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new PoppetFactoryEffect())); + + // At the beginning of your upkeep, you may transform Poppet Factory. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility( + new TransformSourceEffect(), true + )); } private PoppetStitcher(final PoppetStitcher card) { @@ -71,3 +80,57 @@ public final class PoppetStitcher extends CardImpl { return new PoppetStitcher(this); } } + +class PoppetFactoryEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(TokenPredicate.TRUE); + } + + PoppetFactoryEffect() { + super(Duration.WhileOnBattlefield, Outcome.LoseAbility); + staticText = "creature tokens you control lose all abilities and have base power and toughness 3/3"; + } + + private PoppetFactoryEffect(final PoppetFactoryEffect effect) { + super(effect); + } + + @Override + public PoppetFactoryEffect copy() { + return new PoppetFactoryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + )) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + permanent.removeAllAbilities(source.getSourceId(), game); + break; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setModifiedBaseValue(3); + permanent.getToughness().setModifiedBaseValue(3); + } + break; + } + } + 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/p/PortraitOfMichiko.java b/Mage.Sets/src/mage/cards/p/PortraitOfMichiko.java deleted file mode 100644 index 305f77ab110..00000000000 --- a/Mage.Sets/src/mage/cards/p/PortraitOfMichiko.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -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.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PortraitOfMichiko extends CardImpl { - - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( - StaticFilters.FILTER_PERMANENT_CONTROLLED_ARTIFACT_OR_ENCHANTMENT - ); - - public PortraitOfMichiko(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setWhite(true); - this.nightCard = true; - - // Portrait of Michiko gets +1/+1 for each artifact and/or enchantment you control. - this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) - .setText("{this} gets +1/+1 for each artifact and/or enchantment you control"))); - } - - private PortraitOfMichiko(final PortraitOfMichiko card) { - super(card); - } - - @Override - public PortraitOfMichiko copy() { - return new PortraitOfMichiko(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PriceOfFame.java b/Mage.Sets/src/mage/cards/p/PriceOfFame.java index a05d3bfaebe..ec5d1f0683b 100644 --- a/Mage.Sets/src/mage/cards/p/PriceOfFame.java +++ b/Mage.Sets/src/mage/cards/p/PriceOfFame.java @@ -9,10 +9,8 @@ import mage.abilities.effects.keyword.SurveilEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -22,14 +20,7 @@ import java.util.UUID; */ public final class PriceOfFame extends CardImpl { - private static final FilterPermanent filter - = new FilterCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final Condition condition = new SourceTargetsPermanentCondition(filter); + private static final Condition condition = new SourceTargetsPermanentCondition(StaticFilters.FILTER_CREATURE_LEGENDARY); public PriceOfFame(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); diff --git a/Mage.Sets/src/mage/cards/p/PriceOfFreedom.java b/Mage.Sets/src/mage/cards/p/PriceOfFreedom.java new file mode 100644 index 00000000000..a1fcab1bed4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PriceOfFreedom.java @@ -0,0 +1,54 @@ +package mage.cards.p; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayTargetControllerEffect; +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.predicate.Predicates; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PriceOfFreedom extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("artifact or land an opponent controls"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.LAND.getPredicate() + )); + filter.add(TargetController.OPPONENT.getOwnerPredicate()); + } + + public PriceOfFreedom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + this.subtype.add(SubType.LESSON); + + // Destroy target artifact or land an opponent controls. Its controller may search their library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayTargetControllerEffect(true)); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private PriceOfFreedom(final PriceOfFreedom card) { + super(card); + } + + @Override + public PriceOfFreedom copy() { + return new PriceOfFreedom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java b/Mage.Sets/src/mage/cards/p/PrickleFaeries.java deleted file mode 100644 index 525b6089461..00000000000 --- a/Mage.Sets/src/mage/cards/p/PrickleFaeries.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PrickleFaeries extends CardImpl { - - private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, TargetController.ACTIVE); - - public PrickleFaeries(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.FAERIE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Prickle Faeries deals 2 damage to them. - this.addAbility(new BeginningOfUpkeepTriggeredAbility( - Zone.BATTLEFIELD, TargetController.OPPONENT, - new DamageTargetEffect(2, true, "them"), false - ).withInterveningIf(condition)); - } - - private PrickleFaeries(final PrickleFaeries card) { - super(card); - } - - @Override - public PrickleFaeries copy() { - return new PrickleFaeries(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PrimalAmulet.java b/Mage.Sets/src/mage/cards/p/PrimalAmulet.java index fcf75d1ecbf..d4a7aec5b9e 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalAmulet.java +++ b/Mage.Sets/src/mage/cards/p/PrimalAmulet.java @@ -1,30 +1,40 @@ package mage.cards.p; import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyTargetStackObjectEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorcerySpell; import mage.filter.predicate.Predicates; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.game.stack.Spell; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** * @author TheElk801 */ -public final class PrimalAmulet extends CardImpl { +public final class PrimalAmulet extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCard("instant and sorcery spells"); @@ -36,20 +46,31 @@ public final class PrimalAmulet extends CardImpl { } public PrimalAmulet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); - this.secondSideCardClazz = mage.cards.p.PrimalWellspring.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{4}", + "Primal Wellspring", + new CardType[]{CardType.LAND}, new SubType[]{}, ""); + // Primal Amulet // Instant and sorcery spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); // Whenever you cast an instant or sorcery spell, put a charge counter on Primal Amulet. Then if there are four or more charge counters on it, you may remove those counters and transform it. - this.addAbility(new TransformAbility()); Ability ability = new SpellCastControllerTriggeredAbility( new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false ); ability.addEffect(new PrimalAmuletEffect()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Primal Wellspring + // Add one mana of any color. When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy. + Ability manaAbility = new AnyColorManaAbility(); + manaAbility.addEffect(new CreateDelayedTriggeredAbilityEffect(new PrimalWellspringTriggeredAbility( + new CopyTargetStackObjectEffect(true) + .setText("copy that spell and you may choose new targets for the copy")) + )); + this.getRightHalfCard().addAbility(manaAbility); } private PrimalAmulet(final PrimalAmulet card) { @@ -94,3 +115,58 @@ class PrimalAmuletEffect extends OneShotEffect { return true; } } + +class PrimalWellspringTriggeredAbility extends DelayedTriggeredAbility { + + private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + + + public PrimalWellspringTriggeredAbility(Effect effect) { + super(effect, Duration.Custom, true, false); + setTriggerPhrase("When that mana is spent to cast an instant or sorcery spell, "); + } + + private PrimalWellspringTriggeredAbility(final PrimalWellspringTriggeredAbility ability) { + super(ability); + } + + @Override + public PrimalWellspringTriggeredAbility copy() { + return new PrimalWellspringTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.MANA_PAID; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(getSourceId())) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && filter.match(spell, getControllerId(), this, game)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + } + return false; + } + + @Override + public boolean isInactive(Game game) { + if (super.isInactive(game)) { + return true; + } + + // must remove effect on empty mana pool to fix accumulate bug + Player player = game.getPlayer(this.getControllerId()); + if (player == null) { + return true; + } + + // if no mana in pool then it can be discarded + return player.getManaPool().getManaItems().stream().noneMatch(m -> m.getSourceId().equals(getSourceId())); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java deleted file mode 100644 index 024e7274a48..00000000000 --- a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java +++ /dev/null @@ -1,91 +0,0 @@ -package mage.cards.p; - -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.CopyTargetStackObjectEffect; -import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterInstantOrSorcerySpell; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PrimalWellspring extends CardImpl { - - public PrimalWellspring(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // Add one mana of any color. - Ability ability = new AnyColorManaAbility(); - this.addAbility(ability); - - // When that mana is spent to cast an instant or sorcery spell, copy that spell and you may choose new targets for the copy. - this.addAbility(new PrimalWellspringTriggeredAbility( - ability.getOriginalId(), new CopyTargetStackObjectEffect(true) - .setText("copy that spell and you may choose new targets for the copy") - )); - } - - private PrimalWellspring(final PrimalWellspring card) { - super(card); - } - - @Override - public PrimalWellspring copy() { - return new PrimalWellspring(this); - } -} - -class PrimalWellspringTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); - - String abilityOriginalId; - - public PrimalWellspringTriggeredAbility(UUID abilityOriginalId, Effect effect) { - super(Zone.ALL, effect, false); - this.abilityOriginalId = abilityOriginalId.toString(); - setTriggerPhrase("When that mana is used to cast an instant or sorcery spell, "); - } - - private PrimalWellspringTriggeredAbility(final PrimalWellspringTriggeredAbility ability) { - super(ability); - this.abilityOriginalId = ability.abilityOriginalId; - } - - @Override - public PrimalWellspringTriggeredAbility copy() { - return new PrimalWellspringTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.MANA_PAID; - } - - @Override - 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, getControllerId(), this, game)) { - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PrimordialPlasm.java b/Mage.Sets/src/mage/cards/p/PrimordialPlasm.java deleted file mode 100644 index bae0d2e9ea0..00000000000 --- a/Mage.Sets/src/mage/cards/p/PrimordialPlasm.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.p; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect; -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.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PrimordialPlasm extends CardImpl { - - public PrimordialPlasm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.OOZE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - this.nightCard = true; - - // At the beginning of combat on your turn, another target creature gets +2/+2 and loses all abilities until end of turn. - Ability ability = new BeginningOfCombatTriggeredAbility( - new BoostTargetEffect(2, 2) - .setText("another target creature gets +2/+2") - ); - ability.addEffect(new LoseAllAbilitiesTargetEffect(Duration.EndOfTurn) - .setText("and loses all abilities until end of turn")); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE)); - this.addAbility(ability); - } - - private PrimordialPlasm(final PrimordialPlasm card) { - super(card); - } - - @Override - public PrimordialPlasm copy() { - return new PrimordialPlasm(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PrincessYue.java b/Mage.Sets/src/mage/cards/p/PrincessYue.java new file mode 100644 index 00000000000..1ae70920647 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrincessYue.java @@ -0,0 +1,165 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrincessYue extends CardImpl { + + public PrincessYue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Princess Yue dies, if she was a nonland creature, return this card to the battlefield tapped under your control. She's a land named Moon. She gains "{T}: Add {C}." + this.addAbility(new PrincessYueTriggeredAbility()); + + // {T}: Scry 2. + this.addAbility(new SimpleActivatedAbility(new ScryEffect(2), new TapSourceCost())); + } + + private PrincessYue(final PrincessYue card) { + super(card); + } + + @Override + public PrincessYue copy() { + return new PrincessYue(this); + } +} + +class PrincessYueTriggeredAbility extends DiesSourceTriggeredAbility { + + PrincessYueTriggeredAbility() { + super(new PrincessYueReturnEffect()); + } + + private PrincessYueTriggeredAbility(final PrincessYueTriggeredAbility ability) { + super(ability); + } + + @Override + public PrincessYueTriggeredAbility copy() { + return new PrincessYueTriggeredAbility(this); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + return CardUtil + .getEffectValueFromAbility(this, "permanentLeftBattlefield", Permanent.class) + .filter(permanent -> !permanent.isLand(game) && permanent.isCreature(game)) + .isPresent(); + } +} + +class PrincessYueReturnEffect extends OneShotEffect { + + PrincessYueReturnEffect() { + super(Outcome.Benefit); + staticText = "if she was a nonland creature, return this card to the battlefield tapped " + + "under your control. She's a land named Moon. She gains \"{T}: Add {C}.\""; + } + + private PrincessYueReturnEffect(final PrincessYueReturnEffect effect) { + super(effect); + } + + @Override + public PrincessYueReturnEffect copy() { + return new PrincessYueReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getSourceId()); + if (player == null || card == null) { + return false; + } + game.addEffect(new PrincessYueTypeEffect() + .setTargetPointer(new FixedTarget(new MageObjectReference(card, game, 1))), source); + return player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, true, null); + } +} + +class PrincessYueTypeEffect extends ContinuousEffectImpl { + + PrincessYueTypeEffect() { + super(Duration.Custom, Outcome.Benefit); + } + + private PrincessYueTypeEffect(final PrincessYueTypeEffect effect) { + super(effect); + } + + @Override + public PrincessYueTypeEffect copy() { + return new PrincessYueTypeEffect(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 TextChangingEffects_3: + permanent.setName("Moon"); + return true; + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.LAND); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); + return true; + default: + return false; + } + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TextChangingEffects_3: + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + return true; + default: + return false; + } + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrismaticOmen.java b/Mage.Sets/src/mage/cards/p/PrismaticOmen.java index 9a53dca6d17..2b975ebb774 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticOmen.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticOmen.java @@ -5,6 +5,7 @@ import mage.abilities.effects.common.continuous.BecomesAllBasicsControlledEffect import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import java.util.UUID; @@ -17,7 +18,7 @@ public final class PrismaticOmen extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Lands you control are every basic land type in addition to their other types. - this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect())); + this.addAbility(new SimpleStaticAbility(new BecomesAllBasicsControlledEffect(Duration.WhileOnBattlefield))); } private PrismaticOmen(final PrismaticOmen card) { diff --git a/Mage.Sets/src/mage/cards/p/PrisonBreak.java b/Mage.Sets/src/mage/cards/p/PrisonBreak.java index 3ac0e4aacef..f4786cd2ec3 100644 --- a/Mage.Sets/src/mage/cards/p/PrisonBreak.java +++ b/Mage.Sets/src/mage/cards/p/PrisonBreak.java @@ -19,8 +19,8 @@ public final class PrisonBreak extends CardImpl { public PrisonBreak(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); - // Return target creature card from your graveyard to the battlefield with a +1/+1 counter on it. - this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.P1P1.createInstance())); + // Return target creature card from your graveyard to the battlefield with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(true, CounterType.P1P1.createInstance())); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // Mayhem {3}{B} diff --git a/Mage.Sets/src/mage/cards/p/ProfaneProcession.java b/Mage.Sets/src/mage/cards/p/ProfaneProcession.java index 881bab6e555..5f9011a72f0 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneProcession.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneProcession.java @@ -1,19 +1,25 @@ - package mage.cards.p; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +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.TargetCreaturePermanent; import mage.util.CardUtil; @@ -23,24 +29,32 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class ProfaneProcession extends CardImpl { +public final class ProfaneProcession extends TransformingDoubleFacedCard { public ProfaneProcession(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.t.TombOfTheDuskRose.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{W}{B}", + "Tomb of the Dusk Rose", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, ""); + // Profane Procession // {3}{W}{B}: Exile target creature. Then if there are three or more cards exiled with Profane Procession, transform it. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new ManaCostsImpl<>("{3}{W}{B}")); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), ProfaneProcessionCondition.instance, "Then if there are three or more cards exiled with {this}, transform it" )); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Tomb of the Dusk Rose + // {T}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); + + // {2}{W}{B},{T} : Put a creature card exiled with this permanent onto the battlefield under your control. + ability = new SimpleActivatedAbility(new TombOfTheDuskRoseEffect(), new ManaCostsImpl<>("{2}{W}{B}")); + ability.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability); } private ProfaneProcession(final ProfaneProcession card) { @@ -64,3 +78,37 @@ enum ProfaneProcessionCondition implements Condition { .isPresent(); } } + +class TombOfTheDuskRoseEffect extends OneShotEffect { + + TombOfTheDuskRoseEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "put a creature card exiled with this permanent onto the battlefield under your control"; + } + + private TombOfTheDuskRoseEffect(final TombOfTheDuskRoseEffect effect) { + super(effect); + } + + @Override + public TombOfTheDuskRoseEffect copy() { + return new TombOfTheDuskRoseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone == null || exileZone.count(StaticFilters.FILTER_CARD_CREATURE, game) < 1) { + return false; + } + TargetCard targetCard = new TargetCardInExile(StaticFilters.FILTER_CARD_CREATURE, exileZone.getId()); + targetCard.withNotTarget(true); + controller.choose(outcome, targetCard, source, game); + Card card = game.getCard(targetCard.getFirstTarget()); + return card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProfessorZeiAnthropologist.java b/Mage.Sets/src/mage/cards/p/ProfessorZeiAnthropologist.java new file mode 100644 index 00000000000..c4afed6a3db --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProfessorZeiAnthropologist.java @@ -0,0 +1,62 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProfessorZeiAnthropologist extends CardImpl { + + public ProfessorZeiAnthropologist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U/R}{U/R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // {T}, Discard a card: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + + // {1}, {T}, Sacrifice Professor Zei: Return target instant or sorcery card from your graveyard to your hand. Activate only during your turn. + ability = new ActivateIfConditionActivatedAbility( + new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(1), MyTurnCondition.instance + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private ProfessorZeiAnthropologist(final ProfessorZeiAnthropologist card) { + super(card); + } + + @Override + public ProfessorZeiAnthropologist copy() { + return new ProfessorZeiAnthropologist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java index 215d66ae3d5..99bff0ea685 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java +++ b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java @@ -1,9 +1,6 @@ package mage.cards.p; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; @@ -23,6 +20,10 @@ import mage.players.Player; import mage.target.TargetSource; import mage.util.CardUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -92,11 +93,6 @@ class ProtectiveSphereEffect extends PreventionEffectImpl { this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return true; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { manaUsed = (Mana) game.getState().getValue("ProtectiveSphere" + source.getSourceId().toString()); diff --git a/Mage.Sets/src/mage/cards/p/PsionicBlast.java b/Mage.Sets/src/mage/cards/p/PsionicBlast.java index 254ff05fe3d..47ca09ad239 100644 --- a/Mage.Sets/src/mage/cards/p/PsionicBlast.java +++ b/Mage.Sets/src/mage/cards/p/PsionicBlast.java @@ -1,7 +1,6 @@ package mage.cards.p; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,8 +17,7 @@ public final class PsionicBlast extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Psionic Blast deals 4 damage to any target and 2 damage to you. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addEffect(new DamageControllerEffect(2).setText("and 2 damage to you")); + this.getSpellAbility().addEffect(new DamageTargetAndYouEffect(4, 2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/p/PsionicEntity.java b/Mage.Sets/src/mage/cards/p/PsionicEntity.java index 02b0b3a1e10..3c7121bef86 100644 --- a/Mage.Sets/src/mage/cards/p/PsionicEntity.java +++ b/Mage.Sets/src/mage/cards/p/PsionicEntity.java @@ -1,20 +1,18 @@ - package mage.cards.p; -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.effects.common.DamageSelfEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.DamageTargetAndSelfEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author TheElk801 @@ -29,8 +27,7 @@ public final class PsionicEntity extends CardImpl { this.toughness = new MageInt(2); // {tap}: Psionic Entity deals 2 damage to any target and 3 damage to itself. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - ability.addEffect(new DamageSelfEffect(3).setText("and 3 damage to itself")); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndSelfEffect(2, 3), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PsionicSliver.java b/Mage.Sets/src/mage/cards/p/PsionicSliver.java index beb44bdeed6..08eb41473cb 100644 --- a/Mage.Sets/src/mage/cards/p/PsionicSliver.java +++ b/Mage.Sets/src/mage/cards/p/PsionicSliver.java @@ -1,28 +1,24 @@ - package mage.cards.p; -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.effects.common.DamageSelfEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndSelfEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; 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.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * - * @author anonymous - * @see mage.sets.seventhedition.RecklessEmbermage + * @author xenohedron */ public final class PsionicSliver extends CardImpl { @@ -35,11 +31,7 @@ public final class PsionicSliver extends CardImpl { this.toughness = new MageInt(2); // All Sliver creatures have "{T}: This creature deals 2 damage to any target and 3 damage to itself." - Ability ability = new SimpleActivatedAbility( - new DamageTargetEffect(2).setText("This creature deals 2 damage to any target"), - new TapSourceCost() - ); - ability.addEffect(new DamageSelfEffect(3).setText("3 damage to itself.")); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndSelfEffect(2, 3), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility( new SimpleStaticAbility(new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, filter, diff --git a/Mage.Sets/src/mage/cards/p/PunishTheEnemy.java b/Mage.Sets/src/mage/cards/p/PunishTheEnemy.java index aa474c088ee..a56e57185f6 100644 --- a/Mage.Sets/src/mage/cards/p/PunishTheEnemy.java +++ b/Mage.Sets/src/mage/cards/p/PunishTheEnemy.java @@ -1,15 +1,14 @@ - package mage.cards.p; -import java.util.UUID; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** * * @author LevelX2 @@ -20,11 +19,9 @@ public final class PunishTheEnemy extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Punish the Enemy deals 3 damage to target player and 3 damage to target creature. - this.getSpellAbility().addEffect(new DamageTargetEffect(3, true, "target player or planeswalker and 3 damage to target creature")); - Target target = new TargetPlayerOrPlaneswalker(); - this.getSpellAbility().addTarget(target); - target = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(3, 3)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(2)); } private PunishTheEnemy(final PunishTheEnemy card) { diff --git a/Mage.Sets/src/mage/cards/p/Purity.java b/Mage.Sets/src/mage/cards/p/Purity.java index 70aab97b5fc..602024da32d 100644 --- a/Mage.Sets/src/mage/cards/p/Purity.java +++ b/Mage.Sets/src/mage/cards/p/Purity.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; @@ -13,14 +12,15 @@ 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.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.players.Player; +import java.util.UUID; + /** * * @author Pete Rossi @@ -73,8 +73,7 @@ class PurityEffect extends PreventionEffectImpl { if (player != null) { player.gainLife(preventionData.getPreventedDamage(), game, source); } - - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/p/PyreOfTheWorldTree.java b/Mage.Sets/src/mage/cards/p/PyreOfTheWorldTree.java deleted file mode 100644 index 860d255f500..00000000000 --- a/Mage.Sets/src/mage/cards/p/PyreOfTheWorldTree.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.p; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; -import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.filter.StaticFilters; -import mage.target.common.TargetAnyTarget; -import mage.target.common.TargetCardInHand; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class PyreOfTheWorldTree extends CardImpl { - - public PyreOfTheWorldTree(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setRed(true); - this.nightCard = true; - - // Discard a land card: Pyre of the World Tree deals 2 damage to any target. - Ability ability = new SimpleActivatedAbility( - new DamageTargetEffect(2), - new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_LAND_A)) - ); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - - // Whenever you discard a land card, exile the top card of your library. You may play that card this turn. - this.addAbility(new DiscardCardControllerTriggeredAbility( - new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn), - false, StaticFilters.FILTER_CARD_LAND_A - )); - } - - private PyreOfTheWorldTree(final PyreOfTheWorldTree card) { - super(card); - } - - @Override - public PyreOfTheWorldTree copy() { - return new PyreOfTheWorldTree(this); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PyreticPrankster.java b/Mage.Sets/src/mage/cards/p/PyreticPrankster.java index 0263319fa17..a8d94117d1f 100644 --- a/Mage.Sets/src/mage/cards/p/PyreticPrankster.java +++ b/Mage.Sets/src/mage/cards/p/PyreticPrankster.java @@ -1,33 +1,40 @@ package mage.cards.p; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import java.util.UUID; /** * @author TheElk801 */ -public final class PyreticPrankster extends CardImpl { +public final class PyreticPrankster extends TransformingDoubleFacedCard { public PyreticPrankster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEVIL}, "{1}{R}", + "Glistening Goremonger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.DEVIL}, "BR"); - this.subtype.add(SubType.DEVIL); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.g.GlisteningGoremonger.class; + // Pyretic Prankster + this.getLeftHalfCard().setPT(2, 1); // {3}{B/P}: Transform Pyretic Prankster. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{B/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{3}{B/P}"))); + + // Glistening Goremonger + this.getRightHalfCard().setPT(3, 2); + + // When Glistening Goremonger dies, each opponent sacrifices an artifact or creature. + this.getRightHalfCard().addAbility(new DiesSourceTriggeredAbility(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE))); } private PyreticPrankster(final PyreticPrankster card) { diff --git a/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java b/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java index 1d4a2db8358..f099429192d 100644 --- a/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java +++ b/Mage.Sets/src/mage/cards/p/PyrostaticPillar.java @@ -42,7 +42,7 @@ class PyrostaticPillarTriggeredAbility extends TriggeredAbilityImpl { public PyrostaticPillarTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } @@ -76,4 +76,4 @@ class PyrostaticPillarTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a player casts a spell with mana value 3 or less, {this} deals 2 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/q/QuenchableFire.java b/Mage.Sets/src/mage/cards/q/QuenchableFire.java index 0b555526ce7..fac069deee6 100644 --- a/Mage.Sets/src/mage/cards/q/QuenchableFire.java +++ b/Mage.Sets/src/mage/cards/q/QuenchableFire.java @@ -24,7 +24,7 @@ public final class QuenchableFire extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); // It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker’s controller pays {U} before that step. this.getSpellAbility().addEffect(new UnlessPaysDelayedEffect(new ManaCostsImpl<>("{U}"), - new DamageTargetEffect(3, true, "that player or that planeswalker's controller"), PhaseStep.UPKEEP, false, + new DamageTargetEffect(3).withTargetDescription("that player or that planeswalker's controller"), PhaseStep.UPKEEP, false, "It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker's controller pays {U} before that step.")); } diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverBrashBlur.java b/Mage.Sets/src/mage/cards/q/QuicksilverBrashBlur.java new file mode 100644 index 00000000000..3fda66891f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QuicksilverBrashBlur.java @@ -0,0 +1,58 @@ +package mage.cards.q; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LeylineAbility; +import mage.abilities.keyword.PowerUpAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QuicksilverBrashBlur extends CardImpl { + + public QuicksilverBrashBlur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.HERO); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // If Quicksilver, Brash Blur is in your opening hand, you may begin the game with him on the battlefield. + this.addAbility(LeylineAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Power-up -- {4}{R}: Put a +1/+1 counter and a double strike counter on Quicksilver. + Ability ability = new PowerUpAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter"), + new ManaCostsImpl<>("{4}{R}") + ); + ability.addEffect(new AddCountersSourceEffect(CounterType.DOUBLE_STRIKE.createInstance()) + .setText("and a double strike counter on {this}")); + this.addAbility(ability); + } + + private QuicksilverBrashBlur(final QuicksilverBrashBlur card) { + super(card); + } + + @Override + public QuicksilverBrashBlur copy() { + return new QuicksilverBrashBlur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RadiantGrace.java b/Mage.Sets/src/mage/cards/r/RadiantGrace.java index b725e33f23a..ae2c6055941 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantGrace.java +++ b/Mage.Sets/src/mage/cards/r/RadiantGrace.java @@ -5,18 +5,21 @@ import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.PermanentsEnterBattlefieldTappedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.DoubleFacedCardHalf; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; @@ -25,34 +28,52 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class RadiantGrace extends CardImpl { +public final class RadiantGrace extends TransformingDoubleFacedCard { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures enchanted player controls"); + + static { + filter.add(TargetController.ENCHANTED.getControllerPredicate()); + } public RadiantGrace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); - - this.subtype.add(SubType.AURA); - this.secondSideCardClazz = mage.cards.r.RadiantRestraints.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "{W}", + "Radiant Restraints", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "W" + ); + // Radiant Grace // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); + this.getLeftHalfCard().getSpellAbility().addTarget(auraTarget); + this.getLeftHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getLeftHalfCard().addAbility(new EnchantAbility(auraTarget)); // Enchanted creature gets +1/+0 and has vigilance. Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 0)); ability.addEffect(new GainAbilityAttachedEffect( VigilanceAbility.getInstance(), AttachmentType.AURA ).setText("and has vigilance")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // When enchanted creature dies, return Radiant Grace to the battlefield transformed under your control attached to target opponent. - this.addAbility(new TransformAbility()); ability = new DiesAttachedTriggeredAbility( new RadiantGraceEffect(), "enchanted creature", false ); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Radiant Restraints + // Enchant player + TargetPlayer auraTarget2 = new TargetPlayer(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget2); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget2)); + + // Creatures enchanted player controls enter the battlefield tapped. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(filter))); } private RadiantGrace(final RadiantGrace card) { @@ -90,13 +111,13 @@ class RadiantGraceEffect extends OneShotEffect { return false; } - Card card = game.getCard(source.getSourceId()); + DoubleFacedCardHalf card = (DoubleFacedCardHalf) game.getCard(source.getSourceId()); if (card == null) { return false; } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - game.getState().setValue("attachTo:" + source.getSourceId(), player.getId()); + game.getState().setValue("attachTo:" + card.getOtherSide().getId(), 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/RadiantRestraints.java b/Mage.Sets/src/mage/cards/r/RadiantRestraints.java deleted file mode 100644 index 9fa133903b2..00000000000 --- a/Mage.Sets/src/mage/cards/r/RadiantRestraints.java +++ /dev/null @@ -1,56 +0,0 @@ -package mage.cards.r; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.PermanentsEnterBattlefieldTappedEffect; -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.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.TargetPlayer; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RadiantRestraints extends CardImpl { - - private static final FilterCreaturePermanent filter - = new FilterCreaturePermanent("creatures enchanted player controls"); - - static { - filter.add(TargetController.ENCHANTED.getControllerPredicate()); - } - - public RadiantRestraints(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.subtype.add(SubType.CURSE); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant player - TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Creatures enchanted player controls enter the battlefield tapped. - this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(filter))); - } - - private RadiantRestraints(final RadiantRestraints card) { - super(card); - } - - @Override - public RadiantRestraints copy() { - return new RadiantRestraints(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RadiatingLightning.java b/Mage.Sets/src/mage/cards/r/RadiatingLightning.java index 106f3759b40..afd1b213b5d 100644 --- a/Mage.Sets/src/mage/cards/r/RadiatingLightning.java +++ b/Mage.Sets/src/mage/cards/r/RadiatingLightning.java @@ -1,12 +1,10 @@ - package mage.cards.r; -import mage.abilities.effects.common.DamageAllControlledTargetEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndAllControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.TargetPlayer; import java.util.UUID; @@ -20,10 +18,9 @@ public final class RadiatingLightning extends CardImpl { public RadiatingLightning(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}"); - // Radiating Lightning deals 3 damage to target player and 1 damage to each creature that player controls. - this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addEffect(new DamageAllControlledTargetEffect(1, new FilterCreaturePermanent()).setText("and 1 damage to each creature that player controls")); + this.getSpellAbility().addEffect(new DamageTargetAndAllControlledEffect( + 3, 1, StaticFilters.FILTER_PERMANENT_CREATURE)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/r/RaggedRecluse.java b/Mage.Sets/src/mage/cards/r/RaggedRecluse.java index 0f6e003e7ce..fbdd9a94619 100644 --- a/Mage.Sets/src/mage/cards/r/RaggedRecluse.java +++ b/Mage.Sets/src/mage/cards/r/RaggedRecluse.java @@ -1,40 +1,54 @@ package mage.cards.r; -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.ControllerDiscardedThisTurnCondition; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.common.ControllerDiscardedHint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.constants.TargetController; -import mage.watchers.common.DiscardedCardWatcher; import java.util.UUID; /** * @author TheElk801 */ -public final class RaggedRecluse extends CardImpl { +public final class RaggedRecluse extends TransformingDoubleFacedCard { public RaggedRecluse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{B}", + "Odious Witch", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARLOCK}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.PEASANT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.o.OdiousWitch.class; + // Ragged Recluse + this.getLeftHalfCard().setPT(2, 1); // At the beginning of your end step, if you discarded a card this turn, transform Ragged Recluse. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new TransformSourceEffect(), false, ControllerDiscardedThisTurnCondition.instance - ).addHint(ControllerDiscardedHint.instance), new DiscardedCardWatcher()); + ).addHint(ControllerDiscardedHint.instance)); + + // Odious Witch + this.getRightHalfCard().setPT(3, 3); + + // Whenever Odious Witch attacks, defending player loses 1 life and you gain 1 life. + Ability ability = new AttacksTriggeredAbility( + new LoseLifeTargetEffect(1) + .setText("defending player loses 1 life"), + false, null, SetTargetPointer.PLAYER + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(ability); } private RaggedRecluse(final RaggedRecluse card) { diff --git a/Mage.Sets/src/mage/cards/r/RagingKronch.java b/Mage.Sets/src/mage/cards/r/RagingKronch.java index 6073012f684..481e46be31b 100644 --- a/Mage.Sets/src/mage/cards/r/RagingKronch.java +++ b/Mage.Sets/src/mage/cards/r/RagingKronch.java @@ -1,7 +1,8 @@ package mage.cards.r; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -22,7 +23,7 @@ public final class RagingKronch extends CardImpl { this.toughness = new MageInt(3); // Raging Kronch can't attack alone. - this.addAbility(new CantAttackAloneAbility()); + this.addAbility(new SimpleStaticAbility(new CantAttackAloneSourceEffect())); } private RagingKronch(final RagingKronch card) { diff --git a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java index e9db64acfe7..aa004843f01 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java +++ b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java @@ -3,8 +3,7 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -29,11 +28,9 @@ public final class RakdosFirewheeler extends CardImpl { this.toughness = new MageInt(3); // When Rakdos Firewheeler enters the battlefield, it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker. - Effect effect = new DamageTargetEffect(2); - effect.setText("it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); - ability.addTarget(new TargetOpponent()); - ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetAndTargetEffect(2, 2)); + ability.addTarget(new TargetOpponent().setTargetTag(1)); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1).setTargetTag(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java b/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java deleted file mode 100644 index 10e3fac4eb7..00000000000 --- a/Mage.Sets/src/mage/cards/r/RalLeylineProdigy.java +++ /dev/null @@ -1,206 +0,0 @@ -package mage.cards.r; - -import mage.MageIdentifier; -import mage.MageObject; -import mage.MageObjectReference; -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.dynamicvalue.common.InstantAndSorceryCastThisTurn; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageMultiEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.counters.CounterType; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterInstantOrSorceryCard; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetAnyTargetAmount; -import mage.util.CardUtil; - -import java.util.Set; -import java.util.UUID; - -/** - * @author Susucr - */ -public final class RalLeylineProdigy extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("blue permanent other than {this}"); - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); - private static final Hint hint = new ConditionHint(condition, "you control another blue permanent"); - - static { - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(AnotherPredicate.instance); - } - - public RalLeylineProdigy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.RAL); - this.setStartingLoyalty(2); - - this.color.setBlue(true); - this.color.setRed(true); - this.nightCard = true; - - // Ral, Leyline Prodigy enters the battlefield with an additional loyalty counter on him for each instant and sorcery spell you've cast this turn. - this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(), InstantAndSorceryCastThisTurn.YOU, - false) - .setText("with an additional loyalty counter on him for each instant and sorcery spell you've cast this turn")) - .addHint(InstantAndSorceryCastThisTurn.YOU.getHint()) - ); - - // +1: Until your next turn, instant and sorcery spells you cast cost {1} less to cast. - this.addAbility(new LoyaltyAbility(new RalLeylineProdigyCostReductionEffect(), 1)); - - // -2: Ral deals 2 damage divided as you choose among one or two targets. Draw a card if you control a blue permanent other than Ral. - Ability ability = new LoyaltyAbility(new DamageMultiEffect(), -2); - ability.addTarget(new TargetAnyTargetAmount(2)); - ability.addEffect(new ConditionalOneShotEffect( - new DrawCardSourceControllerEffect(1), - condition, "Draw a card if you control a blue permanent other than {this}" - )); - ability.addHint(hint); - this.addAbility(ability); - - // -8: Exile the top eight cards of your library. You may cast instant and sorcery spells from among them this turn without paying their mana costs. - this.addAbility(new LoyaltyAbility(new RalLeylineProdigyMinusEightEffect(), -8) - .setIdentifier(MageIdentifier.WithoutPayingManaCostAlternateCast)); - } - - private RalLeylineProdigy(final RalLeylineProdigy card) { - super(card); - } - - @Override - public RalLeylineProdigy copy() { - return new RalLeylineProdigy(this); - } -} - -class RalLeylineProdigyCostReductionEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterInstantOrSorceryCard("instant and sorcery spells"); - - RalLeylineProdigyCostReductionEffect() { - super(Outcome.Benefit); - this.staticText = "Until your next turn, instant and sorcery spells you cast cost {1} less to cast"; - } - - private RalLeylineProdigyCostReductionEffect(final RalLeylineProdigyCostReductionEffect effect) { - super(effect); - } - - @Override - public RalLeylineProdigyCostReductionEffect copy() { - return new RalLeylineProdigyCostReductionEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - SpellsCostReductionControllerEffect effect = new SpellsCostReductionControllerEffect(filter, 1); - effect.setDuration(Duration.UntilYourNextTurn); - game.addEffect(effect, source); - return true; - } -} - -class RalLeylineProdigyMinusEightEffect extends OneShotEffect { - - RalLeylineProdigyMinusEightEffect() { - super(Outcome.Benefit); - staticText = "Exile the top eight cards of your library. " - + "You may cast instant and sorcery spells from among them this turn without paying their mana costs"; - } - - private RalLeylineProdigyMinusEightEffect(final RalLeylineProdigyMinusEightEffect effect) { - super(effect); - } - - @Override - public RalLeylineProdigyMinusEightEffect copy() { - return new RalLeylineProdigyMinusEightEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); - if (player == null || sourceObject == null) { - return false; - } - Set cards = player.getLibrary().getTopCards(game, 8); - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC()); - player.moveCardsToExile(cards, source, game, true, exileId, sourceObject.getIdName()); - for (Card card : cards) { - if (game.getState().getZone(card.getId()) == Zone.EXILED) { - game.addEffect(new RalLeylineProdigyCastEffect(new MageObjectReference(card, game)), source); - } - } - return true; - } - -} - -class RalLeylineProdigyCastEffect extends AsThoughEffectImpl { - - private final MageObjectReference mor; - - public RalLeylineProdigyCastEffect(MageObjectReference mor) { - super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - this.mor = mor; - } - - private RalLeylineProdigyCastEffect(final RalLeylineProdigyCastEffect effect) { - super(effect); - this.mor = effect.mor; - } - - @Override - public RalLeylineProdigyCastEffect copy() { - return new RalLeylineProdigyCastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (mor.getCard(game) == null) { - discard(); - return false; - } - Card theCard = game.getCard(objectId); - if (theCard == null || !theCard.isInstantOrSorcery(game)) { - return false; - } - UUID mainId = theCard.getMainCard().getId(); // for split cards/MDFC/Adventure cards - if (!source.isControlledBy(affectedControllerId) || !mor.refersTo(mainId, game)) { - return false; - } - allowCardToPlayWithoutMana(mainId, source, affectedControllerId, MageIdentifier.WithoutPayingManaCostAlternateCast, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RalMonsoonMage.java b/Mage.Sets/src/mage/cards/r/RalMonsoonMage.java index c579098b09c..88f51bb66ce 100644 --- a/Mage.Sets/src/mage/cards/r/RalMonsoonMage.java +++ b/Mage.Sets/src/mage/cards/r/RalMonsoonMage.java @@ -1,53 +1,107 @@ package mage.cards.r; -import mage.MageInt; +import mage.MageIdentifier; +import mage.MageObject; +import mage.MageObjectReference; +import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.InstantAndSorceryCastThisTurn; -import mage.constants.Pronoun; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.InstantAndSorceryCastThisTurn; +import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.common.TargetAnyTargetAmount; +import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; /** * @author Susucr */ -public final class RalMonsoonMage extends CardImpl { +public final class RalMonsoonMage extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterInstantOrSorceryCard("Instant and sorcery spells"); + private static final FilterPermanent filterBlue = new FilterPermanent("blue permanent other than {this}"); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filterBlue, true); + private static final Hint hint = new ConditionHint(condition, "you control another blue permanent"); + + static { + filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); + filterBlue.add(AnotherPredicate.instance); + } public RalMonsoonMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{R}", + "Ral, Leyline Prodigy", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.RAL}, "UR" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = RalLeylineProdigy.class; + // Ral, Monsoon Mage + this.getLeftHalfCard().setPT(1, 3); // Instant and sorcery spells you cast cost {1} less to cast. - this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); // Whenever you cast an instant or sorcery spell during your turn, flip a coin. If you lose the flip, Ral, Monsoon Mage deals 1 damage to you. If you win the flip, you may exile Ral. If you do, return him to the battlefield transformed under his owner control. - this.addAbility(new TransformAbility()); - this.addAbility(new RalMonsoonMageTriggeredAbility() + this.getLeftHalfCard().addAbility(new RalMonsoonMageTriggeredAbility() .addHint(InstantAndSorceryCastThisTurn.YOU.getHint())); + + // Ral, Leyline Prodigy + this.getRightHalfCard().setStartingLoyalty(2); + + // Ral, Leyline Prodigy enters the battlefield with an additional loyalty counter on him for each instant and sorcery spell you've cast this turn. + this.getRightHalfCard().addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(), InstantAndSorceryCastThisTurn.YOU, + false) + .setText("with an additional loyalty counter on him for each instant and sorcery spell you've cast this turn")) + .addHint(InstantAndSorceryCastThisTurn.YOU.getHint()) + ); + + // +1: Until your next turn, instant and sorcery spells you cast cost {1} less to cast. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new RalLeylineProdigyCostReductionEffect(), 1)); + + // -2: Ral deals 2 damage divided as you choose among one or two targets. Draw a card if you control a blue permanent other than Ral. + Ability ability = new LoyaltyAbility(new DamageMultiEffect(), -2); + ability.addTarget(new TargetAnyTargetAmount(2)); + ability.addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), + condition, "Draw a card if you control a blue permanent other than {this}" + )); + ability.addHint(hint); + this.getRightHalfCard().addAbility(ability); + + // -8: Exile the top eight cards of your library. You may cast instant and sorcery spells from among them this turn without paying their mana costs. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new RalLeylineProdigyMinusEightEffect(), -8) + .setIdentifier(MageIdentifier.WithoutPayingManaCostAlternateCast)); } private RalMonsoonMage(final RalMonsoonMage card) { @@ -118,3 +172,109 @@ class RalMonsoonMageEffect extends OneShotEffect { return true; } } + +class RalLeylineProdigyCostReductionEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterInstantOrSorceryCard("instant and sorcery spells"); + + RalLeylineProdigyCostReductionEffect() { + super(Outcome.Benefit); + this.staticText = "Until your next turn, instant and sorcery spells you cast cost {1} less to cast"; + } + + private RalLeylineProdigyCostReductionEffect(final RalLeylineProdigyCostReductionEffect effect) { + super(effect); + } + + @Override + public RalLeylineProdigyCostReductionEffect copy() { + return new RalLeylineProdigyCostReductionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + SpellsCostReductionControllerEffect effect = new SpellsCostReductionControllerEffect(filter, 1); + effect.setDuration(Duration.UntilYourNextTurn); + game.addEffect(effect, source); + return true; + } +} + +class RalLeylineProdigyMinusEightEffect extends OneShotEffect { + + RalLeylineProdigyMinusEightEffect() { + super(Outcome.Benefit); + staticText = "Exile the top eight cards of your library. " + + "You may cast instant and sorcery spells from among them this turn without paying their mana costs"; + } + + private RalLeylineProdigyMinusEightEffect(final RalLeylineProdigyMinusEightEffect effect) { + super(effect); + } + + @Override + public RalLeylineProdigyMinusEightEffect copy() { + return new RalLeylineProdigyMinusEightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source); + if (player == null || sourceObject == null) { + return false; + } + Set cards = player.getLibrary().getTopCards(game, 8); + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getStackMomentSourceZCC()); + player.moveCardsToExile(cards, source, game, true, exileId, sourceObject.getIdName()); + for (Card card : cards) { + if (game.getState().getZone(card.getId()) == Zone.EXILED) { + game.addEffect(new RalLeylineProdigyCastEffect(new MageObjectReference(card, game)), source); + } + } + return true; + } +} + +class RalLeylineProdigyCastEffect extends AsThoughEffectImpl { + + private final MageObjectReference mor; + + public RalLeylineProdigyCastEffect(MageObjectReference mor) { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + this.mor = mor; + } + + private RalLeylineProdigyCastEffect(final RalLeylineProdigyCastEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public RalLeylineProdigyCastEffect copy() { + return new RalLeylineProdigyCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (mor.getCard(game) == null) { + discard(); + return false; + } + Card theCard = game.getCard(objectId); + if (theCard == null || !theCard.isInstantOrSorcery(game)) { + return false; + } + UUID mainId = theCard.getMainCard().getId(); // for split cards/MDFC/Adventure cards + if (!source.isControlledBy(affectedControllerId) || !mor.refersTo(mainId, game)) { + return false; + } + allowCardToPlayWithoutMana(mainId, source, affectedControllerId, MageIdentifier.WithoutPayingManaCostAlternateCast, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java index 131cab77f3d..d3e630d8ca4 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java +++ b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java @@ -43,8 +43,9 @@ public final class RampagingFerocidon extends CardImpl { this.addAbility(new SimpleStaticAbility(new CantGainLifeAllEffect())); // Whenever another creature enters the battlefield, Rampaging Ferocidon deals 1 damage to that creature's controller. - this.addAbility(new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that creature's controller"), filter, false, SetTargetPointer.PLAYER)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, + new DamageTargetEffect(1).withTargetDescription("that creature's controller"), + filter, false, SetTargetPointer.PLAYER)); } private RampagingFerocidon(final RampagingFerocidon card) { diff --git a/Mage.Sets/src/mage/cards/r/RampagingGrowth.java b/Mage.Sets/src/mage/cards/r/RampagingGrowth.java index e6def5abe3d..809630b4b94 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingGrowth.java +++ b/Mage.Sets/src/mage/cards/r/RampagingGrowth.java @@ -67,7 +67,7 @@ class RampagingGrowthEffect extends OneShotEffect { } TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND_A); player.searchLibrary(target, source, game); - Card card = player.getLibrary().getCard(target.getTargetController(), game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card == null) { player.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/r/RampagingSoulrager.java b/Mage.Sets/src/mage/cards/r/RampagingSoulrager.java new file mode 100644 index 00000000000..817f93282f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampagingSoulrager.java @@ -0,0 +1,96 @@ +package mage.cards.r; + +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.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.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RampagingSoulrager extends CardImpl { + + public RampagingSoulrager(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // This creature gets +3/+0 as long as there are two or more unlocked doors among Rooms you control. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(3, 0, Duration.WhileOnBattlefield), + RampagingSoulragerCondition.instance, "{this} gets +3/+0 as long as " + + "there are two or more unlocked doors among Rooms you control" + )).addHint(RampagingSoulragerValue.getHint())); + } + + private RampagingSoulrager(final RampagingSoulrager card) { + super(card); + } + + @Override + public RampagingSoulrager copy() { + return new RampagingSoulrager(this); + } +} + +enum RampagingSoulragerCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return RampagingSoulragerValue.instance.calculate(game, source, null) >= 2; + } +} + +enum RampagingSoulragerValue implements DynamicValue { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ROOM); + private static final Hint hint = new ValueHint("Unlocked doors among rooms you control", instance); + + public static Hint getHint() { + return hint; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game) + .stream() + .mapToInt(permanent -> (permanent.isLeftDoorUnlocked() ? 1 : 0) + (permanent.isRightDoorUnlocked() ? 1 : 0)) + .sum(); + } + + @Override + public RampagingSoulragerValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RampagingWerewolf.java b/Mage.Sets/src/mage/cards/r/RampagingWerewolf.java deleted file mode 100644 index b31735e695b..00000000000 --- a/Mage.Sets/src/mage/cards/r/RampagingWerewolf.java +++ /dev/null @@ -1,40 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class RampagingWerewolf extends CardImpl { - - public RampagingWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(6); - this.toughness = new MageInt(4); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Rampaging Werewolf. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private RampagingWerewolf(final RampagingWerewolf card) { - super(card); - } - - @Override - public RampagingWerewolf copy() { - return new RampagingWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RanAndShaw.java b/Mage.Sets/src/mage/cards/r/RanAndShaw.java new file mode 100644 index 00000000000..cf9e298805b --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RanAndShaw.java @@ -0,0 +1,115 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RanAndShaw extends CardImpl { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(Predicates.or( + SubType.DRAGON.getPredicate(), + SubType.LESSON.getPredicate() + )); + } + + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.DRAGON, "Dragons"); + private static final Condition condition = new CompoundCondition( + "you cast them and there are three or more Dragon and/or Lesson cards in your graveyard", + CastFromEverywhereSourceCondition.instance, new CardsInControllerGraveyardCondition(3, filter) + ); + private static final Hint hint = new ValueHint( + "Dragon and Lesson cards in your graveyard", new CardsInControllerGraveyardCount(filter) + ); + + public RanAndShaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // When Ran and Shaw enter, if you cast them and there are three or more Dragon and/or Lesson cards in your graveyard, create a token that's a copy of Ran and Shaw, except it's not legendary. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RanAndShawEffect()) + .withInterveningIf(condition) + .setTriggerPhrase("When {this} enter, ") + .addHint(hint)); + + // {3}{R}: Dragons you control get +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility(new BoostControlledEffect( + 2, 0, Duration.EndOfTurn, filter2 + ), new ManaCostsImpl<>("{3}{R}"))); + } + + private RanAndShaw(final RanAndShaw card) { + super(card); + } + + @Override + public RanAndShaw copy() { + return new RanAndShaw(this); + } +} + +class RanAndShawEffect extends OneShotEffect { + + RanAndShawEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of {this}, except it's not legendary"; + } + + private RanAndShawEffect(final RanAndShawEffect effect) { + super(effect); + } + + @Override + public RanAndShawEffect copy() { + return new RanAndShawEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + return permanent != null + && new CreateTokenCopyTargetEffect() + .setIsntLegendary(true) + .setSavedPermanent(permanent) + .apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaphaelTheMuscle.java b/Mage.Sets/src/mage/cards/r/RaphaelTheMuscle.java new file mode 100644 index 00000000000..329fe3cb076 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaphaelTheMuscle.java @@ -0,0 +1,96 @@ +package mage.cards.r; + +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.CreateTokenEffect; +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.game.permanent.token.MutagenToken; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RaphaelTheMuscle extends CardImpl { + + public RaphaelTheMuscle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Double all damage that creatures you control with counters on them would deal. + this.addAbility(new SimpleStaticAbility(new RaphaelTheMuscleReplacementEffect())); + + // When Raphael enters, create a Mutagen token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MutagenToken()))); + + // Partner--Character select + this.addAbility(PartnerVariantType.CHARACTER_SELECT.makeAbility()); + } + + private RaphaelTheMuscle(final RaphaelTheMuscle card) { + super(card); + } + + @Override + public RaphaelTheMuscle copy() { + return new RaphaelTheMuscle(this); + } +} + +class RaphaelTheMuscleReplacementEffect extends ReplacementEffectImpl { + + RaphaelTheMuscleReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Damage); + staticText = "double all damage that creatures you control with counters on them would deal"; + } + + private RaphaelTheMuscleReplacementEffect(final RaphaelTheMuscleReplacementEffect effect) { + super(effect); + } + + @Override + public RaphaelTheMuscleReplacementEffect copy() { + return new RaphaelTheMuscleReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PLAYER: + case DAMAGE_PERMANENT: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + return permanent != null + && permanent.isCreature(game) + && permanent.isControlledBy(source.getControllerId()) + && permanent.getCounters(game).getTotalCount() > 0; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2)); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaphaelsTechnique.java b/Mage.Sets/src/mage/cards/r/RaphaelsTechnique.java new file mode 100644 index 00000000000..645a3dee9ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaphaelsTechnique.java @@ -0,0 +1,76 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SneakAbility; +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.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RaphaelsTechnique extends CardImpl { + + public RaphaelsTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}{R}"); + + // Sneak {2}{R} + this.addAbility(new SneakAbility(this, "{2}{R}")); + + // Each player may discard their hand and draw seven cards. + this.getSpellAbility().addEffect(new RaphaelsTechniqueEffect()); + } + + private RaphaelsTechnique(final RaphaelsTechnique card) { + super(card); + } + + @Override + public RaphaelsTechnique copy() { + return new RaphaelsTechnique(this); + } +} + +class RaphaelsTechniqueEffect extends OneShotEffect { + + RaphaelsTechniqueEffect() { + super(Outcome.Benefit); + staticText = "each player may discard their hand and draw seven cards"; + } + + private RaphaelsTechniqueEffect(final RaphaelsTechniqueEffect effect) { + super(effect); + } + + @Override + public RaphaelsTechniqueEffect copy() { + return new RaphaelsTechniqueEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List wheelers = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.chooseUse( + Outcome.DrawCard, "Discard your hand and draw seven?", source, game + )) { + game.informPlayers(player.getName() + " chooses to discard their hand and draw seven"); + wheelers.add(player); + } + } + for (Player player : wheelers) { + player.discard(player.getHand(), false, source, game); + player.drawCards(7, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RatchetFieldMedic.java b/Mage.Sets/src/mage/cards/r/RatchetFieldMedic.java index e28788178e3..79abf17bf60 100644 --- a/Mage.Sets/src/mage/cards/r/RatchetFieldMedic.java +++ b/Mage.Sets/src/mage/cards/r/RatchetFieldMedic.java @@ -1,23 +1,28 @@ package mage.cards.r; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.GainLifeControllerTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.LivingMetalAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactCard; +import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.Predicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; @@ -28,27 +33,51 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class RatchetFieldMedic extends CardImpl { +public final class RatchetFieldMedic extends TransformingDoubleFacedCard { + + private static final FilterPermanent filterNontokenArtifacts = new FilterControlledArtifactPermanent(); + + static { + filterNontokenArtifacts.add(TokenPredicate.FALSE); + } public RatchetFieldMedic(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{2}{W}", + "Ratchet, Rescue Racer", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.r.RatchetRescueRacer.class; + // Ratchet, Field Medic + this.getLeftHalfCard().setPT(2, 4); // More Than Meets the Eye {1}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{1}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{1}{W}")); // Lifelink - this.addAbility(LifelinkAbility.getInstance()); + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Whenever you gain life, you may convert Ratchet. When you do, return target artifact card with mana value less than or equal to the amount of life you gained this turn from your graveyard to the battlefield tapped. - this.addAbility(new GainLifeControllerTriggeredAbility( + Ability ability = new GainLifeControllerTriggeredAbility( new RatchetFieldMedicEffect(), true - ), new PlayerGainedLifeWatcher()); + ); + ability.addWatcher(new PlayerGainedLifeWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Ratchet, Rescue Racer + this.getRightHalfCard().setPT(1, 4); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Whenever one or more nontoken artifacts you control are put into a graveyard from the battlefield, convert Ratchet. This ability triggers only once each turn. + this.getRightHalfCard().addAbility(new DiesCreatureTriggeredAbility( + new TransformSourceEffect().setText("convert {this}"), false, filterNontokenArtifacts + ).setTriggerPhrase("Whenever one or more nontoken artifacts you control are put into a graveyard from the battlefield, ") + .setTriggersLimitEachTurn(1)); } private RatchetFieldMedic(final RatchetFieldMedic card) { diff --git a/Mage.Sets/src/mage/cards/r/RatchetRescueRacer.java b/Mage.Sets/src/mage/cards/r/RatchetRescueRacer.java deleted file mode 100644 index 2d56d3c98e7..00000000000 --- a/Mage.Sets/src/mage/cards/r/RatchetRescueRacer.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledArtifactPermanent; -import mage.filter.predicate.permanent.TokenPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RatchetRescueRacer extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledArtifactPermanent(); - - static { - filter.add(TokenPredicate.FALSE); - } - - public RatchetRescueRacer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Whenever one or more nontoken artifacts you control are put into a graveyard from the battlefield, convert Ratchet. This ability triggers only once each turn. - this.addAbility(new DiesCreatureTriggeredAbility( - new TransformSourceEffect().setText("convert {this}"), false, filter - ).setTriggerPhrase("Whenever one or more nontoken artifacts you control " + - "are put into a graveyard from the battlefield, ").setTriggersLimitEachTurn(1)); - } - - private RatchetRescueRacer(final RatchetRescueRacer card) { - super(card); - } - - @Override - public RatchetRescueRacer copy() { - return new RatchetRescueRacer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java b/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java deleted file mode 100644 index ed4bd054210..00000000000 --- a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java +++ /dev/null @@ -1,131 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetOpponentOrPlaneswalker; -import mage.target.targetpointer.EachTargetPointer; - -import java.util.Set; -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class RavagerOfTheFells extends CardImpl { - - public RavagerOfTheFells(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - this.addAbility(TrampleAbility.getInstance()); - - // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. - Ability ability = new TransformIntoSourceTriggeredAbility( - new RavagerOfTheFellsEffect(), false, true - ); - ability.addTarget(new TargetOpponentOrPlaneswalker()); - ability.addTarget(new RavagerOfTheFellsTarget()); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private RavagerOfTheFells(final RavagerOfTheFells card) { - super(card); - } - - @Override - public RavagerOfTheFells copy() { - return new RavagerOfTheFells(this); - } -} - -class RavagerOfTheFellsEffect extends OneShotEffect { - - RavagerOfTheFellsEffect() { - super(Outcome.Damage); - this.setTargetPointer(new EachTargetPointer()); - staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " + - "to up to one target creature that player or that planeswalker's controller controls."; - } - - private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) { - super(effect); - } - - @Override - public RavagerOfTheFellsEffect copy() { - return new RavagerOfTheFellsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - game.damagePlayerOrPermanent( - targetId, 2, source.getSourceId(), source, - game, false, true - ); - } - return true; - } - -} - -class RavagerOfTheFellsTarget extends TargetPermanent { - - RavagerOfTheFellsTarget() { - super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE); - } - - private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) { - super(target); - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - - Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget()); - if (needPlayer == null) { - // playable or not selected - use any - } else { - // filter by controller - possibleTargets.removeIf(id -> { - Permanent permanent = game.getPermanent(id); - return permanent == null - || permanent.getId().equals(source.getFirstTarget()) - || !permanent.isControlledBy(needPlayer.getId()); - }); - } - - return possibleTargets; - } - - @Override - public RavagerOfTheFellsTarget copy() { - return new RavagerOfTheFellsTarget(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RavenEagle.java b/Mage.Sets/src/mage/cards/r/RavenEagle.java new file mode 100644 index 00000000000..86a184ae755 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RavenEagle.java @@ -0,0 +1,94 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +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.Zone; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RavenEagle extends CardImpl { + + public RavenEagle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever this creature enters or attacks, exile up to one target card from a graveyard. If a creature card is exiled this way, create a Clue token. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new RavenEagleEffect()); + ability.addTarget(new TargetCardInGraveyard(0, 1)); + this.addAbility(ability); + + // Whenever you draw your second card each turn, each opponent loses 1 life and you gain 1 life. + ability = new DrawNthCardTriggeredAbility(new LoseLifeOpponentsEffect(1)); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private RavenEagle(final RavenEagle card) { + super(card); + } + + @Override + public RavenEagle copy() { + return new RavenEagle(this); + } +} + +class RavenEagleEffect extends OneShotEffect { + + RavenEagleEffect() { + super(Outcome.Benefit); + staticText = "exile up to one target card from a graveyard. " + + "If a creature card is exiled this way, create a Clue token"; + } + + private RavenEagleEffect(final RavenEagleEffect effect) { + super(effect); + } + + @Override + public RavenEagleEffect copy() { + return new RavenEagleEffect(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; + } + boolean isCreature = card.isCreature(game); + player.moveCards(card, Zone.EXILED, source, game); + if (isCreature) { + game.processAction(); + new ClueArtifactToken().putOntoBattlefield(1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RavenousDemon.java b/Mage.Sets/src/mage/cards/r/RavenousDemon.java index 3feef6706d8..24c32b3ae09 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousDemon.java +++ b/Mage.Sets/src/mage/cards/r/RavenousDemon.java @@ -1,12 +1,16 @@ package mage.cards.r; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; @@ -16,22 +20,37 @@ import java.util.UUID; /** * @author intimidatingant */ -public final class RavenousDemon extends CardImpl { +public final class RavenousDemon extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.HUMAN, "Human"); public RavenousDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); - this.subtype.add(SubType.DEMON); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "{3}{B}{B}", + "Archdemon of Greed", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); - this.secondSideCardClazz = mage.cards.a.ArchdemonOfGreed.class; - - this.power = new MageInt(4); - this.toughness = new MageInt(4); + // Ravenous Demon + this.getLeftHalfCard().setPT(4, 4); // Sacrifice a Human: Transform Ravenous Demon. Activate this ability only any time you could cast a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new SacrificeTargetCost(filter))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new SacrificeTargetCost(filter))); + + // Archdemon of Greed + this.getRightHalfCard().setPT(9, 9); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // At the beginning of your upkeep, sacrifice a Human. If you can't, tap Archdemon of Greed and it deals 9 damage to you. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( + null, new TapSourceEffect(), new SacrificeTargetCost(filter), false + ).addOtherwiseEffect(new DamageControllerEffect(9)) + .setText("sacrifice a Human. If you can't, tap {this} and it deals 9 damage to you"))); } private RavenousDemon(final RavenousDemon card) { diff --git a/Mage.Sets/src/mage/cards/r/RazorPendulum.java b/Mage.Sets/src/mage/cards/r/RazorPendulum.java index 6a0e1d0d6b0..e891923fc6d 100644 --- a/Mage.Sets/src/mage/cards/r/RazorPendulum.java +++ b/Mage.Sets/src/mage/cards/r/RazorPendulum.java @@ -25,7 +25,7 @@ public final class RazorPendulum extends CardImpl { // At the beginning of each player’s end step, if that player has 5 or less life, Razor Pendulum deals 2 damage to that player. this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.EACH_PLAYER, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), false, condition )); } diff --git a/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java b/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java index 42eeff23e9d..20271b68b2e 100644 --- a/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java +++ b/Mage.Sets/src/mage/cards/r/RazorkinNeedlehead.java @@ -35,9 +35,9 @@ public final class RazorkinNeedlehead extends CardImpl { ))); // Whenever an opponent draws a card, Razorkin Needlehead deals 1 damage to them. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect( - 1, true, "them" - ), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility( + new DamageTargetEffect(1).withTargetDescription("them"), + false, true)); } private RazorkinNeedlehead(final RazorkinNeedlehead card) { diff --git a/Mage.Sets/src/mage/cards/r/RealmOfKoh.java b/Mage.Sets/src/mage/cards/r/RealmOfKoh.java new file mode 100644 index 00000000000..f6112e942ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RealmOfKoh.java @@ -0,0 +1,47 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.YouControlABasicLandCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.SpiritWorldToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RealmOfKoh extends CardImpl { + + public RealmOfKoh(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped unless you control a basic land. + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance) + .addHint(YouControlABasicLandCondition.getHint())); + + // {T}: Add {B}. + this.addAbility(new BlackManaAbility()); + + // {3}{B}, {T}: Create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SpiritWorldToken()), new ManaCostsImpl<>("{3}{B}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private RealmOfKoh(final RealmOfKoh card) { + super(card); + } + + @Override + public RealmOfKoh copy() { + return new RealmOfKoh(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java index 2b7e09fafd6..309c2e9b903 100644 --- a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java +++ b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java @@ -1,22 +1,11 @@ package mage.cards.r; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryForFourDifferentCardsEffect; 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.FilterLandCard; -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.constants.PutCards; +import mage.filter.StaticFilters; import java.util.UUID; @@ -29,7 +18,9 @@ public final class RealmsUncharted extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // 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 your library. - this.getSpellAbility().addEffect(new RealmsUnchartedEffect()); + this.getSpellAbility().addEffect(new SearchLibraryForFourDifferentCardsEffect( + StaticFilters.FILTER_CARD_LANDS, PutCards.HAND, false + )); } private RealmsUncharted(final RealmsUncharted card) { @@ -41,61 +32,3 @@ public final class RealmsUncharted extends CardImpl { return new RealmsUncharted(this); } } - -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 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"; - } - - private RealmsUnchartedEffect(final RealmsUnchartedEffect effect) { - super(effect); - } - - @Override - public RealmsUnchartedEffect copy() { - return new RealmsUnchartedEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCardInLibrary targetCards = new TargetCardWithDifferentNameInLibrary(0, 4, filter); - player.searchLibrary(targetCards, source, game); - Cards cards = new CardsImpl(targetCards.getTargets()); - cards.retainZone(Zone.LIBRARY, game); - if (cards.isEmpty()) { - player.shuffleLibrary(source, game); - } - player.revealCards(source, cards, game); - - if (cards.size() > 2) { - TargetOpponent targetOpponent = new TargetOpponent(); - targetOpponent.withNotTarget(true); - player.choose(outcome, targetOpponent, source, game); - Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); - if (opponent != null) { - Cards cardsToKeep = new CardsImpl(cards); - TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, filter2); - if (opponent.choose(Outcome.Discard, cards, targetDiscard, source, 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/RecklessBlaze.java b/Mage.Sets/src/mage/cards/r/RecklessBlaze.java new file mode 100644 index 00000000000..69ba0f2c90d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RecklessBlaze.java @@ -0,0 +1,115 @@ +package mage.cards.r; + +import mage.MageObjectReference; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.mana.BasicManaEffect; +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.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RecklessBlaze extends CardImpl { + + public RecklessBlaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + + this.subtype.add(SubType.LESSON); + + // Reckless Blaze deals 5 damage to each creature. Whenever a creature you control dealt damage this way dies this turn, add {R}. + this.getSpellAbility().addEffect(new RecklessBlazeEffect()); + } + + private RecklessBlaze(final RecklessBlaze card) { + super(card); + } + + @Override + public RecklessBlaze copy() { + return new RecklessBlaze(this); + } +} + +class RecklessBlazeEffect extends OneShotEffect { + + RecklessBlazeEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 5 damage to each creature. " + + "Whenever a creature you control dealt damage this way dies this turn, add {R}"; + } + + private RecklessBlazeEffect(final RecklessBlazeEffect effect) { + super(effect); + } + + @Override + public RecklessBlazeEffect copy() { + return new RecklessBlazeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set morSet = new HashSet<>(); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game + )) { + if (permanent.damage(5, source, game) > 0) { + morSet.add(new MageObjectReference(permanent, game)); + } + } + game.addDelayedTriggeredAbility(new RecklessBlazeTriggeredAbility(morSet), source); + return true; + } +} + +class RecklessBlazeTriggeredAbility extends DelayedTriggeredAbility { + + private final Set morSet = new HashSet<>(); + + RecklessBlazeTriggeredAbility(Set morSet) { + super(new BasicManaEffect(Mana.RedMana(1)), Duration.EndOfTurn, false, false); + this.morSet.addAll(morSet); + this.setTriggerPhrase("Whenever a creature you control dealt damage this way dies this turn, "); + } + + private RecklessBlazeTriggeredAbility(final RecklessBlazeTriggeredAbility ability) { + super(ability); + this.morSet.addAll(ability.morSet); + } + + @Override + public RecklessBlazeTriggeredAbility copy() { + return new RecklessBlazeTriggeredAbility(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; + return zEvent.isDiesEvent() + && zEvent.getTarget() != null + && morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game)) + && zEvent.getTarget().isControlledBy(getControllerId()) + && zEvent.getTarget().isCreature(game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RecklessEmbermage.java b/Mage.Sets/src/mage/cards/r/RecklessEmbermage.java index 9446db91015..4605538e0c5 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessEmbermage.java +++ b/Mage.Sets/src/mage/cards/r/RecklessEmbermage.java @@ -1,20 +1,18 @@ - package mage.cards.r; -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.DamageSelfEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndSelfEffect; 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 Quercitron @@ -30,8 +28,7 @@ public final class RecklessEmbermage extends CardImpl { this.toughness = new MageInt(2); // {1}{R}: Reckless Embermage deals 1 damage to any target and 1 damage to itself. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{1}{R}")); - ability.addEffect(new DamageSelfEffect(1).setText("and 1 damage to itself")); + Ability ability = new SimpleActivatedAbility(new DamageTargetAndSelfEffect(1), new ManaCostsImpl<>("{1}{R}")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RecklessRage.java b/Mage.Sets/src/mage/cards/r/RecklessRage.java index 79b30f0ec35..c052f4c0c8a 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessRage.java +++ b/Mage.Sets/src/mage/cards/r/RecklessRage.java @@ -1,19 +1,15 @@ package mage.cards.r; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; -import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; - /** * @author JayDi85 */ @@ -23,12 +19,9 @@ public final class RecklessRage extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Reckless Rage deals 4 damage to target creature you don't control and 2 damage to target creature you control. - this.getSpellAbility().addTarget(new TargetPermanent(FILTER_CREATURE_YOU_DONT_CONTROL)); - this.getSpellAbility().addEffect(new DamageTargetEffect(4).setUseOnlyTargetPointer(true)); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addEffect(new DamageTargetEffect(2).setUseOnlyTargetPointer(true) - .setText("and 2 damage to target creature you control") - .setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(4, 2)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL).setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(2)); } private RecklessRage(final RecklessRage card) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessStormseeker.java b/Mage.Sets/src/mage/cards/r/RecklessStormseeker.java index 76eeb01bcc3..c4ef345feb8 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessStormseeker.java +++ b/Mage.Sets/src/mage/cards/r/RecklessStormseeker.java @@ -1,14 +1,15 @@ package mage.cards.r; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.HasteAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -19,16 +20,17 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class RecklessStormseeker extends CardImpl { +public final class RecklessStormseeker extends TransformingDoubleFacedCard { public RecklessStormseeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}", + "Storm-Charged Slasher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.s.StormChargedSlasher.class; + // Reckless Stormseeker + this.getLeftHalfCard().setPT(2, 3); // At the beginning of combat on your turn, target creature you control gets +1/+0 and gains haste until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility( @@ -39,10 +41,30 @@ public final class RecklessStormseeker extends CardImpl { HasteAbility.getInstance(), Duration.EndOfTurn ).setText("and gains haste until end of turn")); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Storm-Charged Slasher + this.getRightHalfCard().setPT(3, 4); + + // At the beginning of combat on your turn, target creature you control gets +2/+0 and gains trample and haste until end of turn. + Ability ability2 = new BeginningOfCombatTriggeredAbility( + new BoostTargetEffect(2, 0) + .setText("target creature you control gets +2/+0") + ); + ability2.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample")); + ability2.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and haste until end of turn")); + ability2.addTarget(new TargetControlledCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private RecklessStormseeker(final RecklessStormseeker card) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessWaif.java b/Mage.Sets/src/mage/cards/r/RecklessWaif.java index dae8b27df78..20ceb9378b0 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessWaif.java +++ b/Mage.Sets/src/mage/cards/r/RecklessWaif.java @@ -1,10 +1,9 @@ package mage.cards.r; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +12,26 @@ import java.util.UUID; /** * @author nantuko */ -public final class RecklessWaif extends CardImpl { +public final class RecklessWaif extends TransformingDoubleFacedCard { public RecklessWaif(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{R}", + "Merciless Predator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.m.MercilessPredator.class; - - this.power = new MageInt(1); - this.toughness = new MageInt(1); + // Reckless Waif + this.getLeftHalfCard().setPT(1, 1); // At the beginning of each upkeep, if no spells were cast last turn, transform Reckless Waif. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Merciless Predator + this.getRightHalfCard().setPT(3, 2); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Merciless Predator. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private RecklessWaif(final RecklessWaif card) { diff --git a/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java b/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java deleted file mode 100644 index 51abc490f57..00000000000 --- a/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java +++ /dev/null @@ -1,97 +0,0 @@ -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.game.permanent.Permanent; -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) { - Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (permanent == null) { - return false; - } - - 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/RefractionElemental.java b/Mage.Sets/src/mage/cards/r/RefractionElemental.java deleted file mode 100644 index d68099354eb..00000000000 --- a/Mage.Sets/src/mage/cards/r/RefractionElemental.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.keyword.WardAbility; -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 RefractionElemental extends CardImpl { - - public RefractionElemental(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Ward--Pay 2 life. - this.addAbility(new WardAbility(new PayLifeCost(2), false)); - - // Whenever you cast a spell, Refraction Elemental deals 2 damage to each opponent. - this.addAbility(new SpellCastControllerTriggeredAbility( - new DamagePlayersEffect(2, TargetController.OPPONENT), false - )); - } - - private RefractionElemental(final RefractionElemental card) { - super(card); - } - - @Override - public RefractionElemental copy() { - return new RefractionElemental(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java b/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java deleted file mode 100644 index dc9338acb2e..00000000000 --- a/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java +++ /dev/null @@ -1,134 +0,0 @@ -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 you control enters, 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.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to add counters)", game, source, true); - 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/RestlessBloodseeker.java b/Mage.Sets/src/mage/cards/r/RestlessBloodseeker.java index 25e42d18a6f..9548fa24f98 100644 --- a/Mage.Sets/src/mage/cards/r/RestlessBloodseeker.java +++ b/Mage.Sets/src/mage/cards/r/RestlessBloodseeker.java @@ -1,30 +1,34 @@ package mage.cards.r; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.YouGainedLifeCondition; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.BloodToken; -import mage.watchers.common.PlayerGainedLifeWatcher; import java.util.UUID; /** * @author TheElk801 */ -public final class RestlessBloodseeker extends CardImpl { +public final class RestlessBloodseeker extends TransformingDoubleFacedCard { private static final Condition condition = new YouGainedLifeCondition(); private static final Hint hint = new ConditionHint(condition, "You gained life this turn"); @@ -36,25 +40,42 @@ public final class RestlessBloodseeker extends CardImpl { } public RestlessBloodseeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{1}{B}", + "Bloodsoaked Reveler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B" + ); - this.subtype.add(SubType.VAMPIRE); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BloodsoakedReveler.class; + // Restless Bloodseeker + this.getLeftHalfCard().setPT(1, 3); // At the beginning of your end step, if you gained life this turn, create a Blood token. - this.addAbility(new BeginningOfEndStepTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.YOU, new CreateTokenEffect(new BloodToken()), false, condition - ).addHint(hint), new PlayerGainedLifeWatcher()); + ).addHint(hint)); // Sacrifice two Blood tokens: Transform Restless Bloodseeker. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new TransformSourceEffect(), new SacrificeTargetCost(2, filter) )); + + // Bloodsoaked Reveler + this.getRightHalfCard().setPT(3, 3); + + // At the beginning of your end step, if you gained life this turn, create a Blood token. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility( + TargetController.YOU, new CreateTokenEffect(new BloodToken()), + false, condition + ).addHint(hint)); + + // {4}{B}: Each opponent loses 2 life and you gain 2 life. + Ability ability = new SimpleActivatedAbility( + new LoseLifeOpponentsEffect(2), new ManaCostsImpl<>("{4}{B}") + ); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + this.getRightHalfCard().addAbility(ability); } private RestlessBloodseeker(final RestlessBloodseeker card) { diff --git a/Mage.Sets/src/mage/cards/r/RestrictedOfficeLectureHall.java b/Mage.Sets/src/mage/cards/r/RestrictedOfficeLectureHall.java new file mode 100644 index 00000000000..587c27d6a14 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RestrictedOfficeLectureHall.java @@ -0,0 +1,53 @@ +package mage.cards.r; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RestrictedOfficeLectureHall extends RoomCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures with power 3 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); + } + + public RestrictedOfficeLectureHall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{W}{W}", "{5}{U}{U}"); + + // Restricted Office + // When you unlock this door, destroy all creatures with power 3 or greater. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new DestroyAllEffect(filter), false, true)); + + // Lecture Hall + // Other permanents you control have hexproof. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENTS, true + ))); + } + + private RestrictedOfficeLectureHall(final RestrictedOfficeLectureHall card) { + super(card); + } + + @Override + public RestrictedOfficeLectureHall copy() { + return new RestrictedOfficeLectureHall(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RevealingEye.java b/Mage.Sets/src/mage/cards/r/RevealingEye.java deleted file mode 100644 index 284c7eee69b..00000000000 --- a/Mage.Sets/src/mage/cards/r/RevealingEye.java +++ /dev/null @@ -1,96 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.MenaceAbility; -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.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInHand; -import mage.target.common.TargetOpponent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RevealingEye extends CardImpl { - - public RevealingEye(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.EYE); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility(false)); - - // When this creature transforms into Revealing Eye, target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card, then draws a card. - Ability ability = new TransformIntoSourceTriggeredAbility(new RevealingEyeEffect()); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private RevealingEye(final RevealingEye card) { - super(card); - } - - @Override - public RevealingEye copy() { - return new RevealingEye(this); - } -} - -class RevealingEyeEffect extends OneShotEffect { - - RevealingEyeEffect() { - super(Outcome.Discard); - staticText = "target opponent reveals their hand. You may choose a nonland card from it. " + - "If you do, that player discards that card, then draws a card"; - } - - private RevealingEyeEffect(final RevealingEyeEffect effect) { - super(effect); - } - - @Override - public RevealingEyeEffect copy() { - return new RevealingEyeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player opponent = game.getPlayer(source.getFirstTarget()); - if (controller == null || opponent == null) { - return false; - } - opponent.revealCards(source, opponent.getHand(), game); - if (opponent.getHand().count(StaticFilters.FILTER_CARD_NON_LAND, game) < 1) { - return true; - } - TargetCard target = new TargetCard(0, 1, Zone.HAND, StaticFilters.FILTER_CARD_NON_LAND); - controller.choose(outcome, opponent.getHand(), target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return true; - } - opponent.discard(card, false, source, game); - opponent.drawCards(1, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RhinosRampage.java b/Mage.Sets/src/mage/cards/r/RhinosRampage.java index 8ed68d09334..19280c56afc 100644 --- a/Mage.Sets/src/mage/cards/r/RhinosRampage.java +++ b/Mage.Sets/src/mage/cards/r/RhinosRampage.java @@ -4,50 +4,41 @@ import mage.abilities.Ability; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; 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.FilterArtifactPermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetpointer.EachTargetPointer; +import java.util.List; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author Jmlundeen */ public final class RhinosRampage extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("creature an opponent controls"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public RhinosRampage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R/G}"); - // Target creature you control gets +1/+0 until end of turn. It fights target creature an opponent controls. When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less. this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0)); - this.getSpellAbility().addEffect(new FightTargetsEffect() - .setText("It fights target creature an opponent controls")); this.getSpellAbility().addEffect(new RhinosRampageEffect()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); - + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); } private RhinosRampage(final RhinosRampage card) { @@ -62,10 +53,18 @@ public final class RhinosRampage extends CardImpl { class RhinosRampageEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterArtifactPermanent("noncreature artifact with mana value 3 or less"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); + } + RhinosRampageEffect() { super(Outcome.BoostCreature); - staticText = "When excess damage is dealt to the creature an opponent controls this way, destroy up to one target noncreature " + - "artifact with mana value 3 or less"; + staticText = "it fights target creature an opponent controls. When excess damage is dealt to the creature " + + "an opponent controls this way, destroy up to one target noncreature artifact with mana value 3 or less."; + this.setTargetPointer(new EachTargetPointer()); } protected RhinosRampageEffect(final RhinosRampageEffect effect) { @@ -79,14 +78,20 @@ class RhinosRampageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getTargets().get(1).getFirstTarget()); - if (permanent == null || permanent.getDamage() <= permanent.getToughness().getBaseValue()) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.size() < 2) { return false; } - FilterPermanent filter = new FilterArtifactPermanent("noncreature artifact with mana value 3 or less"); - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 3)); - + int excess = permanents.get(0).fightWithExcess(permanents.get(1), source, game, true); + if (excess < 1) { + return true; + } ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false); ability.addTarget(new TargetPermanent(0, 1, filter)); game.fireReflexiveTriggeredAbility(ability, source); diff --git a/Mage.Sets/src/mage/cards/r/RiphookRaider.java b/Mage.Sets/src/mage/cards/r/RiphookRaider.java deleted file mode 100644 index f423c55b5f8..00000000000 --- a/Mage.Sets/src/mage/cards/r/RiphookRaider.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.keyword.DauntAbility; -import mage.abilities.keyword.NightboundAbility; -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 RiphookRaider extends CardImpl { - - public RiphookRaider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(4); - this.color.setGreen(true); - this.nightCard = true; - - // Riphook Raider can't be blocked by creatures with power 2 or less. - this.addAbility(new DauntAbility()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private RiphookRaider(final RiphookRaider card) { - super(card); - } - - @Override - public RiphookRaider copy() { - return new RiphookRaider(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/Rivendell.java b/Mage.Sets/src/mage/cards/r/Rivendell.java index 2f0d377e354..b7903de9c0e 100644 --- a/Mage.Sets/src/mage/cards/r/Rivendell.java +++ b/Mage.Sets/src/mage/cards/r/Rivendell.java @@ -3,7 +3,7 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; -import mage.abilities.condition.common.YouControlPermanentCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.keyword.ScryEffect; @@ -12,8 +12,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; import java.util.UUID; @@ -22,28 +20,22 @@ import java.util.UUID; */ public final class Rivendell extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter); - public Rivendell(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); // Rivendell enters the battlefield tapped unless you control a legendary creature. - this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint())); + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); // {T}: Add {U}. this.addAbility(new BlueManaAbility()); // {1}{U}, {T}: Scry 2. Activate only if you control a legendary creature. Ability ability = new ActivateIfConditionActivatedAbility( - new ScryEffect(2, false), new ManaCostsImpl<>("{1}{U}"), condition + new ScryEffect(2, false), new ManaCostsImpl<>("{1}{U}"), + YouControlALegendaryCreatureCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RoarOfTheFifthPeople.java b/Mage.Sets/src/mage/cards/r/RoarOfTheFifthPeople.java deleted file mode 100644 index 6a4bbba19af..00000000000 --- a/Mage.Sets/src/mage/cards/r/RoarOfTheFifthPeople.java +++ /dev/null @@ -1,100 +0,0 @@ -package mage.cards.r; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.TrampleAbility; -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.Duration; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.game.permanent.token.DinosaurVanillaToken; -import mage.target.common.TargetCardInLibrary; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class RoarOfTheFifthPeople extends CardImpl { - - private static final FilterCard filterCard = new FilterCard("Dinosaur card"); - private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.DINOSAUR, "Dinosaurs you control"); - - static { - filterCard.add(SubType.DINOSAUR.getPredicate()); - } - - public RoarOfTheFifthPeople(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.color.setGreen(true); - this.color.setRed(true); - this.subtype.add(SubType.SAGA); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.) - SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_IV); - - // I -- Create two 3/3 green Dinosaur creature tokens. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new DinosaurVanillaToken(), 2)); - - // II -- Roar of the Fifth People gains "Creatures you control have '{T}: Add {R}, {G}, or {W}.'" - - // Note: splitting the mana ability in 3 makes it easier on the UI. - Ability gainedAbility = new SimpleStaticAbility(new GainAbilityControlledEffect( - new RedManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false - ).setText("Creatures you control have '{T}: Add {R}")); - gainedAbility.addEffect(new GainAbilityControlledEffect( - new GreenManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false - ).setText(", {G}")); - gainedAbility.addEffect(new GainAbilityControlledEffect( - new WhiteManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false - ).setText(", or {W}.'")); - - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, - new GainAbilitySourceEffect(gainedAbility, Duration.WhileOnBattlefield) - .setText("{this} gains \"Creatures you control have '{T}: Add {R}, {G}, or {W}.'\"") - ); - - // III -- Search your library for a Dinosaur card, reveal it, put it into your hand, then shuffle. - TargetCardInLibrary target = new TargetCardInLibrary(filterCard); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new SearchLibraryPutInHandEffect(target, true)); - - // IV -- Dinosaurs you control gain double strike and trample until end of turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_IV, - new GainAbilityControlledEffect( - DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filter - ).setText("Dinosaurs you control gain double strike"), - new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, filter - ).setText("and trample until end of turn") - ); - - this.addAbility(sagaAbility); - } - - private RoarOfTheFifthPeople(final RoarOfTheFifthPeople card) { - super(card); - } - - @Override - public RoarOfTheFifthPeople copy() { - return new RoarOfTheFifthPeople(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RoaringFurnaceSteamingSauna.java b/Mage.Sets/src/mage/cards/r/RoaringFurnaceSteamingSauna.java new file mode 100644 index 00000000000..eb2952bd22d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoaringFurnaceSteamingSauna.java @@ -0,0 +1,50 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Duration; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoaringFurnaceSteamingSauna extends RoomCard { + + public RoaringFurnaceSteamingSauna(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{1}{R}", "{3}{U}{U}"); + + // Roaring Furnace + // When you unlock this door, this Room deals damage equal to the number of cards in your hand to target creature an opponent controls. + Ability ability = new UnlockThisDoorTriggeredAbility(new DamageTargetEffect(CardsInControllerHandCount.ANY), false, true); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.getLeftHalfCard().addAbility(ability); + + // Steaming Sauna + // You have no maximum hand size. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET + ))); + + // At the beginning of your end step, draw a card. + this.getRightHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1))); + } + + private RoaringFurnaceSteamingSauna(final RoaringFurnaceSteamingSauna card) { + super(card); + } + + @Override + public RoaringFurnaceSteamingSauna copy() { + return new RoaringFurnaceSteamingSauna(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Rockalanche.java b/Mage.Sets/src/mage/cards/r/Rockalanche.java new file mode 100644 index 00000000000..a4843ce6bbd --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Rockalanche.java @@ -0,0 +1,51 @@ +package mage.cards.r; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Rockalanche extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterControlledPermanent(SubType.FOREST, "Forests you control"), null + ); + private static final Hint hint = new ValueHint("Forests you control", xValue); + + public Rockalanche(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + this.subtype.add(SubType.LESSON); + + // Earthbend X, where X is the number of Forests you control. + this.getSpellAbility().addEffect(new EarthbendTargetEffect(xValue, true)); + this.getSpellAbility().addTarget(new TargetControlledLandPermanent()); + this.getSpellAbility().addHint(hint); + + // Flashback {5}{G} + this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{5}{G}"))); + } + + private Rockalanche(final Rockalanche card) { + super(card); + } + + @Override + public Rockalanche copy() { + return new Rockalanche(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoilingVortex.java b/Mage.Sets/src/mage/cards/r/RoilingVortex.java index 3f64b096d95..e35c3e043aa 100644 --- a/Mage.Sets/src/mage/cards/r/RoilingVortex.java +++ b/Mage.Sets/src/mage/cards/r/RoilingVortex.java @@ -32,15 +32,15 @@ public final class RoilingVortex extends CardImpl { // At the beginning of each player's upkeep, Roiling Vortex deals 1 damage to them. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "them"), + TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("them"), false )); // Whenever a player casts a spell, if no mana was spent to cast that spell, Roiling Vortex deals 5 damage to that player. - this.addAbility(new SpellCastAllTriggeredAbility(new DamageTargetEffect( - 5, true, "that player", - "if no mana was spent to cast that spell, {this}" - ), filter, false, SetTargetPointer.PLAYER)); + this.addAbility(new SpellCastAllTriggeredAbility( + new DamageTargetEffect(5) + .setText("if no mana was spent to cast that spell, {this} deals 5 damage to that player"), + filter, false, SetTargetPointer.PLAYER)); // {R}: Your opponents can't gain life this turn. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/r/RonaHeraldOfInvasion.java b/Mage.Sets/src/mage/cards/r/RonaHeraldOfInvasion.java index e7c1e9c5f58..745037e126b 100644 --- a/Mage.Sets/src/mage/cards/r/RonaHeraldOfInvasion.java +++ b/Mage.Sets/src/mage/cards/r/RonaHeraldOfInvasion.java @@ -1,28 +1,34 @@ package mage.cards.r; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterSpell; +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 RonaHeraldOfInvasion extends CardImpl { +public final class RonaHeraldOfInvasion extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("a legendary spell"); @@ -31,26 +37,34 @@ public final class RonaHeraldOfInvasion extends CardImpl { } public RonaHeraldOfInvasion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{U}", + "Rona, Tolarian Obliterator", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.WIZARD}, "UB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.r.RonaTolarianObliterator.class; + // Rona, Herald of Invasion + this.getLeftHalfCard().setPT(1, 3); // Whenever you cast a legendary spell, untap Rona, Herald of Invasion. - this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, false)); // {T}: Draw a card, then discard a card. - this.addAbility(new SimpleActivatedAbility( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( new DrawDiscardControllerEffect(1, 1), new TapSourceCost() )); // {5}{B/P}: Transform Rona. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{B/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{B/P}"))); + + // Rona, Tolarian Obliterator + this.getRightHalfCard().setPT(5, 5); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever a source deals damage to Rona, Tolarian Obliterator, that source's controller exiles a card from their hand at random. If it's a land card, you may put it onto the battlefield under your control. Otherwise, you may cast it without paying its mana cost. + this.getRightHalfCard().addAbility(new RonaTolarianObliteratorTriggeredAbility()); } private RonaHeraldOfInvasion(final RonaHeraldOfInvasion card) { @@ -62,3 +76,75 @@ public final class RonaHeraldOfInvasion extends CardImpl { return new RonaHeraldOfInvasion(this); } } + +class RonaTolarianObliteratorTriggeredAbility extends TriggeredAbilityImpl { + + RonaTolarianObliteratorTriggeredAbility() { + super(Zone.BATTLEFIELD, new RonaTolarianObliteratorEffect()); + } + + private RonaTolarianObliteratorTriggeredAbility(final RonaTolarianObliteratorTriggeredAbility ability) { + super(ability); + } + + @Override + public RonaTolarianObliteratorTriggeredAbility copy() { + return new RonaTolarianObliteratorTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(getSourceId())) { + this.getEffects().setTargetPointer(new FixedTarget(game.getControllerId(event.getSourceId()))); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever a source deals damage to {this}, that source's controller exiles a card " + + "from their hand at random. If it's a land card, you may put it onto the battlefield " + + "under your control. Otherwise, you may cast it without paying its mana cost."; + } +} + +class RonaTolarianObliteratorEffect extends OneShotEffect { + + RonaTolarianObliteratorEffect() { + super(Outcome.Benefit); + } + + private RonaTolarianObliteratorEffect(final RonaTolarianObliteratorEffect effect) { + super(effect); + } + + @Override + public RonaTolarianObliteratorEffect copy() { + return new RonaTolarianObliteratorEffect(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 = player.getHand().getRandom(game); + if (card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + if (!card.isLand(game)) { + return CardUtil.castSpellWithAttributesForFree(controller, source, game, card); + } + return controller.chooseUse(Outcome.PutLandInPlay, "Put " + card.getIdName() + " onto the battlefield?", source, game) + && controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RonaTolarianObliterator.java b/Mage.Sets/src/mage/cards/r/RonaTolarianObliterator.java deleted file mode 100644 index 65f8672be31..00000000000 --- a/Mage.Sets/src/mage/cards/r/RonaTolarianObliterator.java +++ /dev/null @@ -1,124 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.TrampleAbility; -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.target.targetpointer.FixedTarget; -import mage.util.CardUtil; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RonaTolarianObliterator extends CardImpl { - - public RonaTolarianObliterator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setBlue(true); - this.color.setBlack(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Whenever a source deals damage to Rona, Tolarian Obliterator, that source's controller exiles a card from their hand at random. If it's a land card, you may put it onto the battlefield under your control. Otherwise, you may cast it without paying its mana cost. - this.addAbility(new RonaTolarianObliteratorTriggeredAbility()); - } - - private RonaTolarianObliterator(final RonaTolarianObliterator card) { - super(card); - } - - @Override - public RonaTolarianObliterator copy() { - return new RonaTolarianObliterator(this); - } -} - -class RonaTolarianObliteratorTriggeredAbility extends TriggeredAbilityImpl { - - RonaTolarianObliteratorTriggeredAbility() { - super(Zone.BATTLEFIELD, new RonaTolarianObliteratorEffect()); - } - - private RonaTolarianObliteratorTriggeredAbility(final RonaTolarianObliteratorTriggeredAbility ability) { - super(ability); - } - - @Override - public RonaTolarianObliteratorTriggeredAbility copy() { - return new RonaTolarianObliteratorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getTargetId().equals(getSourceId())) { - this.getEffects().setTargetPointer(new FixedTarget(game.getControllerId(event.getSourceId()))); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever a source deals damage to {this}, that source's controller exiles a card " + - "from their hand at random. If it's a land card, you may put it onto the battlefield " + - "under your control. Otherwise, you may cast it without paying its mana cost."; - } -} - -class RonaTolarianObliteratorEffect extends OneShotEffect { - - RonaTolarianObliteratorEffect() { - super(Outcome.Benefit); - } - - private RonaTolarianObliteratorEffect(final RonaTolarianObliteratorEffect effect) { - super(effect); - } - - @Override - public RonaTolarianObliteratorEffect copy() { - return new RonaTolarianObliteratorEffect(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 = player.getHand().getRandom(game); - if (card == null) { - return false; - } - player.moveCards(card, Zone.EXILED, source, game); - if (!card.isLand(game)) { - return CardUtil.castSpellWithAttributesForFree(controller, source, game, card); - } - return controller.chooseUse(Outcome.PutLandInPlay, "Put " + card.getIdName() + " onto the battlefield?", source, game) - && controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RooftopSaboteurs.java b/Mage.Sets/src/mage/cards/r/RooftopSaboteurs.java deleted file mode 100644 index 7d78c7b665f..00000000000 --- a/Mage.Sets/src/mage/cards/r/RooftopSaboteurs.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.r; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class RooftopSaboteurs extends CardImpl { - - public RooftopSaboteurs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.MOONFOLK); - this.subtype.add(SubType.NINJA); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Rooftop Saboteurs deals combat damage to a player or battle, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility( - new DrawCardSourceControllerEffect(1), false)); - } - - private RooftopSaboteurs(final RooftopSaboteurs card) { - super(card); - } - - @Override - public RooftopSaboteurs copy() { - return new RooftopSaboteurs(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RoughshodMentor.java b/Mage.Sets/src/mage/cards/r/RoughshodMentor.java index fc21bdd7489..bc71ac7a23e 100644 --- a/Mage.Sets/src/mage/cards/r/RoughshodMentor.java +++ b/Mage.Sets/src/mage/cards/r/RoughshodMentor.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; @@ -10,19 +8,21 @@ 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.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** * * @author North */ public final class RoughshodMentor extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Green creatures"); + private static final FilterPermanent filter = new FilterCreaturePermanent("Green creatures"); static { filter.add(new ColorPredicate(ObjectColor.GREEN)); diff --git a/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java b/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java new file mode 100644 index 00000000000..59794334c6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RuinousWaterbending.java @@ -0,0 +1,87 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.WaterbendAbility; +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.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RuinousWaterbending extends CardImpl { + + public RuinousWaterbending(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, you may waterbend {4}. + this.addAbility(new WaterbendAbility(4)); + + // All creatures get -2/-2 until end of turn. If this spell's additional cost was paid, whenever a creature dies this turn, you gain 1 life. + this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new CreateDelayedTriggeredAbilityEffect(new RuinousWaterbendingAbility()), + WaterbendedCondition.instance, "If this spell's additional cost was paid, " + + "whenever a creature dies this turn, you gain 1 life" + )); + } + + private RuinousWaterbending(final RuinousWaterbending card) { + super(card); + } + + @Override + public RuinousWaterbending copy() { + return new RuinousWaterbending(this); + } +} + +class RuinousWaterbendingAbility extends DelayedTriggeredAbility { + + RuinousWaterbendingAbility() { + super(new GainLifeEffect(1), Duration.EndOfTurn, false); + setLeavesTheBattlefieldTrigger(true); + setTriggerPhrase("Whenever a creature dies this turn, "); + } + + private RuinousWaterbendingAbility(final RuinousWaterbendingAbility ability) { + super(ability); + } + + @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; + return zEvent.isDiesEvent() && zEvent.getTarget().isCreature(game); + } + + @Override + public RuinousWaterbendingAbility copy() { + return new RuinousWaterbendingAbility(this); + } + + @Override + public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { + return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RumbleArena.java b/Mage.Sets/src/mage/cards/r/RumbleArena.java new file mode 100644 index 00000000000..47dd8997ea4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RumbleArena.java @@ -0,0 +1,48 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RumbleArena extends CardImpl { + + public RumbleArena(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When this land enters, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {1}, {T}: Add one mana of any color. + Ability ability = new AnyColorManaAbility(new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private RumbleArena(final RumbleArena card) { + super(card); + } + + @Override + public RumbleArena copy() { + return new RumbleArena(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RunoStromkirk.java b/Mage.Sets/src/mage/cards/r/RunoStromkirk.java index 158b4130dae..c4b16f5fa67 100644 --- a/Mage.Sets/src/mage/cards/r/RunoStromkirk.java +++ b/Mage.Sets/src/mage/cards/r/RunoStromkirk.java @@ -1,25 +1,29 @@ package mage.cards.r; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -27,29 +31,45 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class RunoStromkirk extends CardImpl { +public final class RunoStromkirk extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterAttackingCreature("another attacking creature"); + + static { + filter.add(AnotherPredicate.instance); + } public RunoStromkirk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.CLERIC}, "{1}{U}{B}", + "Krothuss, Lord of the Deep", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.KRAKEN, SubType.HORROR}, "UB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(1); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.k.KrothussLordOfTheDeep.class; + // Runo Stromkirk + this.getLeftHalfCard().setPT(1, 4); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Runo Stromkirk enters the battlefield, put up to one target creature card from your graveyard on top of your library. Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true)); ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If a creature card with mana value 6 or greater is revealed this way, transform Runo Stromkirk. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RunoStromkirkEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new RunoStromkirkEffect())); + + // Krothuss, Lord of the Deep + this.getRightHalfCard().setPT(3, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Krothuss, Lord of the Deep attacks, create a tapped and attacking token that's a copy of another target attacking creature. If that creature is a Kraken, Leviathan, Octopus, or Serpent, create two of those tokens instead. + Ability ability2 = new AttacksTriggeredAbility(new KrothussLordOfTheDeepEffect()); + ability2.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(ability2); } private RunoStromkirk(final RunoStromkirk card) { @@ -104,3 +124,38 @@ class RunoStromkirkEffect extends OneShotEffect { return true; } } + + +class KrothussLordOfTheDeepEffect extends OneShotEffect { + + KrothussLordOfTheDeepEffect() { + super(Outcome.Benefit); + staticText = "create a tapped and attacking token that's a copy of another target attacking creature. " + + "If that creature is a Kraken, Leviathan, Octopus, or Serpent, create two of those tokens instead"; + } + + private KrothussLordOfTheDeepEffect(final KrothussLordOfTheDeepEffect effect) { + super(effect); + } + + @Override + public KrothussLordOfTheDeepEffect copy() { + return new KrothussLordOfTheDeepEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + int count = permanent.hasSubtype(SubType.KRAKEN, game) + || permanent.hasSubtype(SubType.LEVIATHAN, game) + || permanent.hasSubtype(SubType.OCTOPUS, game) + || permanent.hasSubtype(SubType.SERPENT, game) ? 2 : 1; + return new CreateTokenCopyTargetEffect( + null, null, + false, count, true, true + ).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RuthlessWaterbender.java b/Mage.Sets/src/mage/cards/r/RuthlessWaterbender.java new file mode 100644 index 00000000000..261f0d79329 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RuthlessWaterbender.java @@ -0,0 +1,45 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.WaterbendCost; +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 RuthlessWaterbender extends CardImpl { + + public RuthlessWaterbender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Waterbend {2}: This creature gets +1/+1 until end of turn. Activate only during your turn. + this.addAbility(new ActivateIfConditionActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new WaterbendCost(2), MyTurnCondition.instance + )); + } + + private RuthlessWaterbender(final RuthlessWaterbender card) { + super(card); + } + + @Override + public RuthlessWaterbender copy() { + return new RuthlessWaterbender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SacredBoon.java b/Mage.Sets/src/mage/cards/s/SacredBoon.java new file mode 100644 index 00000000000..d0d119952d5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SacredBoon.java @@ -0,0 +1,83 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class SacredBoon extends CardImpl { + + public SacredBoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Prevent the next 3 damage that would be dealt to target creature this turn. At the beginning of the next end step, put a +0/+1 counter on that creature for each 1 damage prevented this way. + this.getSpellAbility().addEffect(new SacredBoonPreventDamageTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SacredBoon(final SacredBoon card) { + super(card); + } + + @Override + public SacredBoon copy() { + return new SacredBoon(this); + } +} + +class SacredBoonPreventDamageTargetEffect extends PreventionEffectImpl { + + + SacredBoonPreventDamageTargetEffect(Duration duration) { + super(duration, 3, false); + staticText = "Prevent the next 3 damage that would be dealt to target creature this turn. At the beginning of the next end step, put a +0/+1 counter on that creature for each 1 damage prevented this way."; + } + + private SacredBoonPreventDamageTargetEffect(final SacredBoonPreventDamageTargetEffect effect) { + super(effect); + } + + @Override + public SacredBoonPreventDamageTargetEffect copy() { + return new SacredBoonPreventDamageTargetEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new AddCountersTargetEffect(CounterType.P0P1.createInstance(preventionEffectData.getPreventedDamage())) + .setTargetPointer(new FixedTarget(targetPermanent, game))); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return super.applies(event, source, game) && source.getTargets().getFirstTarget().equals(event.getTargetId()); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java b/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java index 156aa64d14e..1196d5bd0e4 100644 --- a/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java +++ b/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java @@ -1,17 +1,19 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.condition.common.NotTransformedCondition; import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.CardsInAllHandsCount; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -21,20 +23,20 @@ import java.util.UUID; /** * @author fireshoes */ -public final class SageOfAncientLore extends CardImpl { +public final class SageOfAncientLore extends TransformingDoubleFacedCard { public SageOfAncientLore(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(0); - this.toughness = new MageInt(0); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{4}{G}", + "Werewolf of Ancient Hunger", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.w.WerewolfOfAncientHunger.class; + // Sage of Ancient Lore + this.getLeftHalfCard().setPT(0, 0); // Sage of Ancient Lore's power and toughness are each equal to the number of cards in your hand. - this.addAbility(new SimpleStaticAbility( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( Zone.ALL, new ConditionalContinuousEffect( new SetBasePowerToughnessSourceEffect(CardsInControllerHandCount.ANY), NotTransformedCondition.instance, @@ -43,11 +45,31 @@ public final class SageOfAncientLore extends CardImpl { )); // When Sage of Ancient Lore enters the battlefield, draw a card. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); // At the beginning of each upkeep, if no spells were cast last turn, transform Sage of Ancient Lore. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Werewolf of Ancient Hunger + this.getRightHalfCard().setPT(0, 0); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Werewolf of Ancient Hunger's power and toughness are each equal to the total number of cards in all players' hands. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, + new ConditionalContinuousEffect( + new SetBasePowerToughnessSourceEffect(CardsInAllHandsCount.instance), NotTransformedCondition.instance, + "{this}'s power and toughness are each equal to the total number of cards in all players' hands" + ) + )); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf of Ancient Hunger. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private SageOfAncientLore(final SageOfAncientLore card) { diff --git a/Mage.Sets/src/mage/cards/s/SaheelisLattice.java b/Mage.Sets/src/mage/cards/s/SaheelisLattice.java index ebd54c53d84..0822ba96df3 100644 --- a/Mage.Sets/src/mage/cards/s/SaheelisLattice.java +++ b/Mage.Sets/src/mage/cards/s/SaheelisLattice.java @@ -1,36 +1,60 @@ package mage.cards.s; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.util.CardUtil; import java.util.UUID; /** * @author TheElk801 */ -public final class SaheelisLattice extends CardImpl { +public final class SaheelisLattice extends TransformingDoubleFacedCard { public SaheelisLattice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}"); - this.secondSideCardClazz = mage.cards.m.MastercraftRaptor.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{R}", + "Mastercraft Raptor", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.DINOSAUR}, "R" + ); // When Saheeli's Lattice enters the battlefield, you may discard a card. If you do, draw two cards. - this.addAbility(new EntersBattlefieldTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new DoIfCostPaid(new DrawCardSourceControllerEffect(2), new DiscardCardCost()) )); // Craft with one or more Dinosaurs {4}{R} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{4}{R}", "one or more Dinosaurs", "other Dinosaurs you control " + "or Dinosaur cards in your graveyard", 1, Integer.MAX_VALUE, SubType.DINOSAUR.getPredicate() )); + + // Mastercraft Raptor + this.getRightHalfCard().setPT(0, 4); + + // Mastercraft Raptor's power is equal to the total power of the exiled cards used to craft it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, new SetBasePowerSourceEffect(MastercraftRaptorValue.instance) + .setText("{this}'s power is equal to the total power of the exiled cards used to craft it") + )); } private SaheelisLattice(final SaheelisLattice card) { @@ -42,3 +66,45 @@ public final class SaheelisLattice extends CardImpl { return new SaheelisLattice(this); } } + +enum MastercraftRaptorValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Card sourceCard = game.getCard(sourceAbility.getSourceId()); + if (sourceCard == null) { + return 0; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, sourceCard.getMainCard().getId(), + sourceCard.getMainCard().getZoneChangeCounter(game) - 1 + )); + if (exileZone == null) { + return 0; + } + return exileZone + .getCards(game) + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum(); + } + + @Override + public MastercraftRaptorValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java b/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java index 4abb51be552..5d04c5a6172 100644 --- a/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java +++ b/Mage.Sets/src/mage/cards/s/SaltRoadPackbeast.java @@ -7,8 +7,10 @@ import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.keyword.AffinityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AffinityType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -27,10 +29,8 @@ public final class SaltRoadPackbeast extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(3); - // This spell costs {1} less to cast for each creature you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SpellCostReductionForEachSourceEffect(1, CreaturesYouControlCount.SINGULAR) - ).addHint(CreaturesYouControlHint.instance)); + // Affinity for creatures + this.addAbility(new AffinityAbility(AffinityType.CREATURES)); // When this creature enters, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfAll.java b/Mage.Sets/src/mage/cards/s/SanctumOfAll.java index c82143cf4e6..ddbfa2bead4 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfAll.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfAll.java @@ -1,22 +1,15 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.search.SearchLibraryGraveyardPutOntoBattlefieldEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; 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.*; import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -24,18 +17,13 @@ import mage.game.permanent.Permanent; import java.util.UUID; /** - * * @author htrajan */ public final class SanctumOfAll extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); private static final FilterCard filterCard = new FilterCard("Shrine card"); - static final PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter); - static { - filter.add(SubType.SHRINE.getPredicate()); filterCard.add(SubType.SHRINE.getPredicate()); } @@ -49,7 +37,7 @@ public final class SanctumOfAll extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SearchLibraryGraveyardPutOntoBattlefieldEffect(filterCard), true)); // If an ability of another Shrine you control triggers while you control six or more Shrines, that ability triggers an additional time. - this.addAbility(new SimpleStaticAbility(new SanctumOfAllTriggerEffect()).addHint(new ValueHint("Shrines you control", count))); + this.addAbility(new SimpleStaticAbility(new SanctumOfAllTriggerEffect()).addHint(ShrinesYouControlCount.getHint())); } private SanctumOfAll(final SanctumOfAll card) { @@ -94,7 +82,7 @@ class SanctumOfAllTriggerEffect extends ReplacementEffectImpl { // Only triggers of the controller of Sanctum of All if (source.isControlledBy(event.getPlayerId())) { // Only trigger while you control six or more Shrines - int numShrines = SanctumOfAll.count.calculate(game, source, this); + int numShrines = ShrinesYouControlCount.FOR_EACH.calculate(game, source, this); if (numShrines >= 6) { // Only for triggers of other Shrines Permanent permanent = game.getPermanent(event.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java b/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java index 1f4696f4578..e4c6560fe95 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java @@ -1,34 +1,23 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** * @author jmharmon */ - public final class SanctumOfCalmWaters extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); - private static final PermanentsOnBattlefieldCount xValue = new PermanentsOnBattlefieldCount(filter); - - static { - filter.add(SubType.SHRINE.getPredicate()); - } - public SanctumOfCalmWaters(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); @@ -36,10 +25,9 @@ public final class SanctumOfCalmWaters extends CardImpl { this.subtype.add(SubType.SHRINE); // At the beginning of your precombat main phase, you may draw X cards, where X is the number of Shrines you control. If you do, discard a card. - Ability ability = new BeginningOfFirstMainTriggeredAbility(new DrawCardSourceControllerEffect(xValue) - .setText("you may draw X cards, where X is the number of Shrines you control"), true - ) - .addHint(new ValueHint("Shrines you control", xValue)); + Ability ability = new BeginningOfFirstMainTriggeredAbility( + new DrawCardSourceControllerEffect(ShrinesYouControlCount.WHERE_X), true + ).addHint(ShrinesYouControlCount.getHint()); ability.addEffect(new DiscardControllerEffect(1).setText("If you do, discard a card")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfFruitfulHarvest.java b/Mage.Sets/src/mage/cards/s/SanctumOfFruitfulHarvest.java index 049e03d2f0f..8e8767a1feb 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfFruitfulHarvest.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfFruitfulHarvest.java @@ -1,48 +1,33 @@ package mage.cards.s; import mage.Mana; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.mana.DynamicManaEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** - * * @author htrajan */ public final class SanctumOfFruitfulHarvest extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); - private static final PermanentsOnBattlefieldCount xValue = new PermanentsOnBattlefieldCount(filter); - - static { - filter.add(SubType.SHRINE.getPredicate()); - } - public SanctumOfFruitfulHarvest(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); // At the beginning of your precombat main phase, add X mana of any one color, where X is the number of Shrines you control. - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DynamicManaEffect( - Mana.AnyMana(1), - xValue, - "add X mana of any one color, where X is the number of Shrines you control", - true) - ) - .addHint(new ValueHint("Shrines you control", xValue))); + this.addAbility(new BeginningOfFirstMainTriggeredAbility(new DynamicManaEffect( + Mana.AnyMana(1), ShrinesYouControlCount.WHERE_X, + "add X mana of any one color, where X is the number of Shrines you control", true + )).addHint(ShrinesYouControlCount.getHint())); } private SanctumOfFruitfulHarvest(final SanctumOfFruitfulHarvest card) { diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java index cfaafbf6305..6f62d277894 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java @@ -3,18 +3,15 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.hint.ValueHint; 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.predicate.Predicates; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreatureOrPlaneswalker; @@ -28,12 +25,12 @@ import java.util.UUID; public final class SanctumOfShatteredHeights extends CardImpl { private static final FilterCard filter = new FilterCard("a land card or Shrine card"); - private static final FilterPermanent filterShrinesOnly = new FilterControlledPermanent("Shrine you control"); - private static final PermanentsOnBattlefieldCount xValue = new PermanentsOnBattlefieldCount(filterShrinesOnly); static { - filter.add(Predicates.or(CardType.LAND.getPredicate(), SubType.SHRINE.getPredicate())); - filterShrinesOnly.add(SubType.SHRINE.getPredicate()); + filter.add(Predicates.or( + CardType.LAND.getPredicate(), + SubType.SHRINE.getPredicate() + )); } public SanctumOfShatteredHeights(UUID ownerId, CardSetInfo setInfo) { @@ -43,10 +40,11 @@ public final class SanctumOfShatteredHeights extends CardImpl { this.subtype.add(SubType.SHRINE); // {1}, Discard a land card or Shrine card: Sanctum of Shattered Heights deals X damage to target creature or planeswalker, where X is the number of Shrines you control. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(xValue) - .setText("{this} deals X damage to target creature or planeswalker, where X is the number of Shrines you control"), - new ManaCostsImpl<>("{1}")) - .addHint(new ValueHint("Shrines you control", xValue)); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(ShrinesYouControlCount.WHERE_X) + .setText("{this} deals X damage to target creature or planeswalker, where X is the number of Shrines you control"), + new GenericManaCost(1) + ).addHint(ShrinesYouControlCount.getHint()); ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); ability.addTarget(new TargetCreatureOrPlaneswalker()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfStoneFangs.java b/Mage.Sets/src/mage/cards/s/SanctumOfStoneFangs.java index b21aa11d119..b88130ad6f5 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfStoneFangs.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfStoneFangs.java @@ -1,46 +1,34 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import java.util.UUID; /** - * * @author htrajan */ public final class SanctumOfStoneFangs extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(""); - private static final PermanentsOnBattlefieldCount xValue = new PermanentsOnBattlefieldCount(filter, null); - - static { - filter.add(SubType.SHRINE.getPredicate()); - } - public SanctumOfStoneFangs(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.SHRINE); // At the beginning of your precombat main phase, each opponent loses X life and you gain X life, where X is the number of Shrines you control. Ability ability = new BeginningOfFirstMainTriggeredAbility( - new LoseLifeOpponentsEffect(xValue).setText("each opponent loses X life") - ) - .addHint(new ValueHint("Shrines you control", xValue)); - ability.addEffect(new GainLifeEffect(xValue).setText("and you gain X life, where X is the number of Shrines you control")); + new LoseLifeOpponentsEffect(ShrinesYouControlCount.WHERE_X).setText("each opponent loses X life") + ).addHint(ShrinesYouControlCount.getHint()); + ability.addEffect(new GainLifeEffect(ShrinesYouControlCount.WHERE_X).setText("and you gain X life, where X is the number of Shrines you control")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java b/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java deleted file mode 100644 index e83c6d87bb0..00000000000 --- a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.s; - -import java.util.UUID; -import mage.Mana; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.ControllerLifeCount; -import mage.abilities.mana.DynamicManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; - -/** - * - * @author LevelX2 - */ -public final class SanctumOfTheSun extends CardImpl { - - public SanctumOfTheSun(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // (Transforms from Azor's Gateway.) - - // {T}: Add X mana of any one color, where X is your life total. - this.addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), ControllerLifeCount.instance, new TapSourceCost(), - "Add X mana of any one color, where X is your life total", true)); - - } - - private SanctumOfTheSun(final SanctumOfTheSun card) { - super(card); - } - - @Override - public SanctumOfTheSun copy() { - return new SanctumOfTheSun(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfTranquilLight.java b/Mage.Sets/src/mage/cards/s/SanctumOfTranquilLight.java index ab18f92bf92..3edd1fe5766 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfTranquilLight.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfTranquilLight.java @@ -4,19 +4,14 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.TapTargetEffect; -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.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -40,7 +35,7 @@ public final class SanctumOfTranquilLight extends CardImpl { ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each Shrine you control")); ability.addTarget(new TargetCreaturePermanent()); ability.setCostAdjuster(SanctumOfTranquilLightAdjuster.instance); - this.addAbility(ability.addHint(SanctumOfTranquilLightAdjuster.getHint())); + this.addAbility(ability.addHint(ShrinesYouControlCount.getHint())); } private SanctumOfTranquilLight(final SanctumOfTranquilLight card) { @@ -56,19 +51,11 @@ public final class SanctumOfTranquilLight extends CardImpl { enum SanctumOfTranquilLightAdjuster implements CostAdjuster { instance; - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SHRINE); - private static final DynamicValue count = new PermanentsOnBattlefieldCount(filter); - private static final Hint hint = new ValueHint("Shrines you control", count); - - public static Hint getHint() { - return hint; - } - @Override public void reduceCost(Ability ability, Game game) { Player controller = game.getPlayer(ability.getControllerId()); if (controller != null) { - CardUtil.reduceCost(ability, count.calculate(game, ability, null)); + CardUtil.reduceCost(ability, ShrinesYouControlCount.FOR_EACH.calculate(game, ability, null)); } } } diff --git a/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java b/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java new file mode 100644 index 00000000000..6dd8e0abd56 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SandbenderScavengers.java @@ -0,0 +1,105 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +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.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SandbenderScavengers extends CardImpl { + + public SandbenderScavengers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever you sacrifice another permanent, put a +1/+1 counter on this creature. + this.addAbility(new SacrificePermanentTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT + )); + + // When this creature dies, you may exile it. When you do, return target creature card with mana value less than or equal to this creature's power from your graveyard to the battlefield. + this.addAbility(new DiesSourceTriggeredAbility(new SandbenderScavengersEffect())); + } + + private SandbenderScavengers(final SandbenderScavengers card) { + super(card); + } + + @Override + public SandbenderScavengers copy() { + return new SandbenderScavengers(this); + } +} + +class SandbenderScavengersEffect extends OneShotEffect { + + SandbenderScavengersEffect() { + super(Outcome.Benefit); + staticText = "you may exile it. When you do, return target creature card with mana value " + + "less than or equal to this creature's power from your graveyard to the battlefield."; + } + + private SandbenderScavengersEffect(final SandbenderScavengersEffect effect) { + super(effect); + } + + @Override + public SandbenderScavengersEffect copy() { + return new SandbenderScavengersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = Optional + .ofNullable(source.getSourceObject(game)) + .filter(Card.class::isInstance) + .map(Card.class::cast) + .filter(c -> c.getZoneChangeCounter(game) != source.getStackMomentSourceZCC() + 1) + .orElse(null); + if (player == null || card == null || !player.chooseUse( + Outcome.Exile, "Exile " + card.getName() + '?', source, game + )) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + int mv = Optional + .ofNullable((Permanent) getValue("permanentLeftBattlefield")) + .map(MageObject::getPower) + .map(MageInt::getValue) + .orElse(0); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); + FilterCard filter = new FilterCreatureCard("creature card with mana value " + mv + " or less"); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, mv + 1)); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SandbendersStorm.java b/Mage.Sets/src/mage/cards/s/SandbendersStorm.java new file mode 100644 index 00000000000..3326fa727bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SandbendersStorm.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SandbendersStorm extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public SandbendersStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); + + // Choose one-- + // * Destroy target creature with power 4 or greater. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // * Earthbend 3. + this.getSpellAbility().addMode(new Mode(new EarthbendTargetEffect(3)) + .addTarget(new TargetControlledLandPermanent())); + } + + private SandbendersStorm(final SandbendersStorm card) { + super(card); + } + + @Override + public SandbendersStorm copy() { + return new SandbendersStorm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SandmanShiftingScoundrel.java b/Mage.Sets/src/mage/cards/s/SandmanShiftingScoundrel.java index ff40e6a5215..9d4c489c2a4 100644 --- a/Mage.Sets/src/mage/cards/s/SandmanShiftingScoundrel.java +++ b/Mage.Sets/src/mage/cards/s/SandmanShiftingScoundrel.java @@ -43,7 +43,7 @@ public final class SandmanShiftingScoundrel extends CardImpl { this.addAbility(new DauntAbility()); // {3}{G}{G}: Return this card and target land card from your graveyard to the battlefield tapped. - Ability ability = new SimpleActivatedAbility( + Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true) .setText("return this card"), new ManaCostsImpl<>("{3}{G}{G}") diff --git a/Mage.Sets/src/mage/cards/s/SandswirlWanderglyph.java b/Mage.Sets/src/mage/cards/s/SandswirlWanderglyph.java deleted file mode 100644 index eb39b60b2c4..00000000000 --- a/Mage.Sets/src/mage/cards/s/SandswirlWanderglyph.java +++ /dev/null @@ -1,123 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.RestrictionEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.watchers.common.PlayersAttackedThisTurnWatcher; - -import java.util.UUID; - -/** - * - * @author notgreat - */ -public final class SandswirlWanderglyph extends CardImpl { - private static final FilterSpell filter = new FilterSpell("a spell during their turn"); - - static { - filter.add(TargetController.ACTIVE.getControllerPredicate()); - } - public SandswirlWanderglyph(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.GOLEM); - this.power = new MageInt(5); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setWhite(true); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever an opponent casts a spell during their turn, they can't attack you or planeswalkers you control this turn. - this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, - new CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(), filter, false, SetTargetPointer.PLAYER)); - - // Each opponent who attacked you or a planeswalker you control this turn can't cast spells. - this.addAbility(new SimpleStaticAbility(new SandswirlWanderglyphCantCastEffect()), new PlayersAttackedThisTurnWatcher()); - } - - private SandswirlWanderglyph(final SandswirlWanderglyph card) { - super(card); - } - - @Override - public SandswirlWanderglyph copy() { - return new SandswirlWanderglyph(this); - } -} - -class SandswirlWanderglyphCantCastEffect extends ContinuousRuleModifyingEffectImpl { - - SandswirlWanderglyphCantCastEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "Each opponent who attacked you or a planeswalker you control this turn can't cast spells"; - } - - private SandswirlWanderglyphCantCastEffect(final SandswirlWanderglyphCantCastEffect effect) { - super(effect); - } - - @Override - public SandswirlWanderglyphCantCastEffect copy() { - return new SandswirlWanderglyphCantCastEffect(this); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (game.isActivePlayer(event.getPlayerId()) && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - PlayersAttackedThisTurnWatcher watcher = game.getState().getWatcher(PlayersAttackedThisTurnWatcher.class); - return watcher != null && watcher.hasPlayerAttackedPlayerOrControlledPlaneswalker(event.getPlayerId(), source.getControllerId()); - } - return false; - } - -} -class CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect extends RestrictionEffect { - CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect() { - super(Duration.EndOfTurn); - staticText = "they can't attack you or planeswalkers you control this turn"; - } - - private CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(final CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect effect) { - super(effect); - } - - @Override - public CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect copy() { - return new CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(this); - } - - @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { - if (game.getPlayer(defenderId) != null){ - return !(source.getControllerId().equals(defenderId)); - } - Permanent defender = game.getPermanent(defenderId); - if (defender != null && defender.isPlaneswalker()){ - return !(source.getControllerId().equals(defender.getControllerId())); - } - return true; - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getControllerId().equals(getTargetPointer().getFirst(game, source)); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SavagePackmate.java b/Mage.Sets/src/mage/cards/s/SavagePackmate.java deleted file mode 100644 index f60351ab25a..00000000000 --- a/Mage.Sets/src/mage/cards/s/SavagePackmate.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.keyword.NightboundAbility; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SavagePackmate extends CardImpl { - - public SavagePackmate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Other creatures you control get +1/+0. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 1, 0, Duration.WhileOnBattlefield, true - ))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private SavagePackmate(final SavagePackmate card) { - super(card); - } - - @Override - public SavagePackmate copy() { - return new SavagePackmate(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java index 408833a25e4..b250229b7e1 100644 --- a/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java +++ b/Mage.Sets/src/mage/cards/s/ScabClanBerserker.java @@ -37,7 +37,7 @@ public final class ScabClanBerserker extends CardImpl { // Whenever an opponent casts a noncreature spell, if Scab-Clan Berserker is renowned, Scab-Clan Berserker deals 2 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( Zone.BATTLEFIELD, - new DamageTargetEffect(2, true, "that player"), + new DamageTargetEffect(2).withTargetDescription("that player"), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.PLAYER ).withInterveningIf(RenownedSourceCondition.THIS)); } diff --git a/Mage.Sets/src/mage/cards/s/Scald.java b/Mage.Sets/src/mage/cards/s/Scald.java index 48f66774b62..fcad2a81c3e 100644 --- a/Mage.Sets/src/mage/cards/s/Scald.java +++ b/Mage.Sets/src/mage/cards/s/Scald.java @@ -29,7 +29,7 @@ public final class Scald extends CardImpl { // Whenever a player taps an Island for mana, Scald deals 1 damage to that player. this.addAbility(new TapForManaAllTriggeredAbility( - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), filter, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/s/ScaldingViper.java b/Mage.Sets/src/mage/cards/s/ScaldingViper.java index f0e17f5f7fc..7006ac38719 100644 --- a/Mage.Sets/src/mage/cards/s/ScaldingViper.java +++ b/Mage.Sets/src/mage/cards/s/ScaldingViper.java @@ -34,7 +34,7 @@ public final class ScaldingViper extends AdventureCard { // Whenever an opponent casts a spell with mana value 3 or less, Scalding Viper deals 1 damage to that player. this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player"), + Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player"), filter, false, SetTargetPointer.PLAYER )); diff --git a/Mage.Sets/src/mage/cards/s/ScarringMemories.java b/Mage.Sets/src/mage/cards/s/ScarringMemories.java new file mode 100644 index 00000000000..4ffccfad733 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScarringMemories.java @@ -0,0 +1,62 @@ +package mage.cards.s; + +import mage.abilities.common.CastAsThoughItHadFlashIfConditionAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +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.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterAttackingCreature; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScarringMemories extends CardImpl { + + private static final FilterPermanent filter = new FilterAttackingCreature("you control an attacking legendary creature"); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition); + + public ScarringMemories(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + this.subtype.add(SubType.LESSON); + + // You may cast this spell as though it had flash if you control an attacking legendary creature. + this.addAbility(new CastAsThoughItHadFlashIfConditionAbility( + condition, "you may cast this spell as though it had flash if you control an attacking legendary creature." + )); + + // Target opponent sacrifices a creature of their choice, discards a card, and loses 3 life. + this.getSpellAbility().addEffect(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent")); + this.getSpellAbility().addEffect(new DiscardTargetEffect(1).setText(", discards a card")); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(3).setText(", and loses 3 life")); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private ScarringMemories(final ScarringMemories card) { + super(card); + } + + @Override + public ScarringMemories copy() { + return new ScarringMemories(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScarsOfTheVeteran.java b/Mage.Sets/src/mage/cards/s/ScarsOfTheVeteran.java new file mode 100644 index 00000000000..3ddecf5249f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScarsOfTheVeteran.java @@ -0,0 +1,99 @@ +package mage.cards.s; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.filter.common.FilterOwnedCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * + * @author notgreat + */ +public final class ScarsOfTheVeteran extends CardImpl { + + private static final FilterOwnedCard filter + = new FilterOwnedCard("a white card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + public ScarsOfTheVeteran(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); + + + // You may exile a white card from your hand rather than pay Scars of the Veteran's mana cost. + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); + + // Prevent the next 7 damage that would be dealt to any target this turn. If it’s a creature, put a +0/+1 counter on it for each 1 damage prevented this way at the beginning of the next end step. + this.getSpellAbility().addEffect(new ScarsOfTheVeteranPreventDamageTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + private ScarsOfTheVeteran(final ScarsOfTheVeteran card) { + super(card); + } + + @Override + public ScarsOfTheVeteran copy() { + return new ScarsOfTheVeteran(this); + } +} + +class ScarsOfTheVeteranPreventDamageTargetEffect extends PreventionEffectImpl { + + ScarsOfTheVeteranPreventDamageTargetEffect(Duration duration) { + super(duration, 7, false); + staticText = "Prevent the next 7 damage that would be dealt to any target this turn. If it's a creature, put a +0/+1 counter on it for each 1 damage prevented this way at the beginning of the next end step."; + } + + private ScarsOfTheVeteranPreventDamageTargetEffect(final ScarsOfTheVeteranPreventDamageTargetEffect effect) { + super(effect); + } + + @Override + public ScarsOfTheVeteranPreventDamageTargetEffect copy() { + return new ScarsOfTheVeteranPreventDamageTargetEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new AddCountersTargetEffect(CounterType.P0P1.createInstance(preventionEffectData.getPreventedDamage())) + .setTargetPointer(new FixedTarget(targetPermanent, game))); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + return false; + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return super.applies(event, source, game) && source.getTargets().getFirstTarget().equals(event.getTargetId()); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/ScornedVillager.java b/Mage.Sets/src/mage/cards/s/ScornedVillager.java index 2092c0575b1..cd2d04dbf6d 100644 --- a/Mage.Sets/src/mage/cards/s/ScornedVillager.java +++ b/Mage.Sets/src/mage/cards/s/ScornedVillager.java @@ -1,37 +1,52 @@ package mage.cards.s; -import mage.MageInt; +import mage.Mana; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.keyword.VigilanceAbility; import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import java.util.UUID; /** * @author North */ -public final class ScornedVillager extends CardImpl { +public final class ScornedVillager extends TransformingDoubleFacedCard { public ScornedVillager(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}", + "Moonscarred Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.m.MoonscarredWerewolf.class; + // Scorned Villager + this.getLeftHalfCard().setPT(1, 1); // {tap}: Add {G}. - this.addAbility(new GreenManaAbility()); + this.getLeftHalfCard().addAbility(new GreenManaAbility()); // At the beginning of each upkeep, if no spells were cast last turn, transform Scorned Villager. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Moonscarred Werewolf + this.getRightHalfCard().setPT(2, 2); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // {tap}: Add {G}{G}. + this.getRightHalfCard().addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new TapSourceCost())); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Moonscarred Werewolf. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private ScornedVillager(final ScornedVillager card) { diff --git a/Mage.Sets/src/mage/cards/s/ScreechingBat.java b/Mage.Sets/src/mage/cards/s/ScreechingBat.java index 102b78c99a2..9323279b673 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingBat.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingBat.java @@ -1,14 +1,13 @@ package mage.cards.s; -import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -17,25 +16,32 @@ import java.util.UUID; /** * @author nantuko */ -public final class ScreechingBat extends CardImpl { +public final class ScreechingBat extends TransformingDoubleFacedCard { public ScreechingBat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); - this.subtype.add(SubType.BAT); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BAT}, "{2}{B}", + "Stalking Vampire", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "B" + ); - this.secondSideCardClazz = mage.cards.s.StalkingVampire.class; + // Screeching Bat + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // At the beginning of your upkeep, you may pay {2}{B}{B}. If you do, transform Screeching Bat. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( + Ability transformAbility = new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}{B}") - ))); + )); + this.getLeftHalfCard().addAbility(transformAbility); + + // Stalking Vampire + this.getRightHalfCard().setPT(5, 5); + + // At the beginning of your upkeep, you may pay {2}{B}{B}. If you do, transform Screeching Bat. + this.getRightHalfCard().addAbility(transformAbility.copy()); } private ScreechingBat(final ScreechingBat card) { diff --git a/Mage.Sets/src/mage/cards/s/ScroungedScythe.java b/Mage.Sets/src/mage/cards/s/ScroungedScythe.java deleted file mode 100644 index 0d3e7b0075b..00000000000 --- a/Mage.Sets/src/mage/cards/s/ScroungedScythe.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.s; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.EquippedHasSubtypeCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.EquipAbility; -import mage.abilities.keyword.MenaceAbility; -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 fireshoes - */ -public final class ScroungedScythe extends CardImpl { - - private static final Condition condition = new EquippedHasSubtypeCondition(SubType.HUMAN); - - public ScroungedScythe(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.subtype.add(SubType.EQUIPMENT); - - this.nightCard = true; - - // Equipped creature gets +1/+1. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); - - // As long as equipped creature is a Human, it has menace. - this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( - new GainAbilityAttachedEffect(new MenaceAbility(false), AttachmentType.EQUIPMENT), - condition, "As long as equipped creature is a Human, it has menace. " + - "(It can't be blocked except by two or more creatures.)" - ))); - - // Equip {2} - this.addAbility(new EquipAbility(2, false)); - } - - private ScroungedScythe(final ScroungedScythe card) { - super(card); - } - - @Override - public ScroungedScythe copy() { - return new ScroungedScythe(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SeafaringWerewolf.java b/Mage.Sets/src/mage/cards/s/SeafaringWerewolf.java deleted file mode 100644 index 56b3b8c7054..00000000000 --- a/Mage.Sets/src/mage/cards/s/SeafaringWerewolf.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.CantBeBlockedSourceAbility; -import mage.abilities.keyword.NightboundAbility; -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 SeafaringWerewolf extends CardImpl { - - public SeafaringWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.color.setGreen(true); - this.nightCard = true; - - // Seafaring Werewolf can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); - - // Whenever Seafaring Werewolf deals combat damage to a player, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new DrawCardSourceControllerEffect(1), false - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private SeafaringWerewolf(final SeafaringWerewolf card) { - super(card); - } - - @Override - public SeafaringWerewolf copy() { - return new SeafaringWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SearchForAzcanta.java b/Mage.Sets/src/mage/cards/s/SearchForAzcanta.java index 348a84913c5..c51f4756a0c 100644 --- a/Mage.Sets/src/mage/cards/s/SearchForAzcanta.java +++ b/Mage.Sets/src/mage/cards/s/SearchForAzcanta.java @@ -1,15 +1,19 @@ package mage.cards.s; import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +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.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.keyword.SurveilEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -19,22 +23,41 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class SearchForAzcanta extends CardImpl { +public final class SearchForAzcanta extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("a noncreature, nonland card"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } public SearchForAzcanta(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); - - this.secondSideCardClazz = mage.cards.a.AzcantaTheSunkenRuin.class; - - this.supertype.add(SuperType.LEGENDARY); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{U}", + "Azcanta, The Sunken Ruin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "U" + ); + // Search for Azcanta // At the beginning of your upkeep, look at the top card of your library. You may put it into your graveyard. Then if you have seven or more cards in your graveyard, you may transform Search for Azcanta. Ability ability = new BeginningOfUpkeepTriggeredAbility( new SurveilEffect(1, false) ); ability.addEffect(new SearchForAzcantaEffect()); - this.addAbility(new TransformAbility()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Azcanta, The Sunken Ruin + // {T} : Add {U}. + this.getRightHalfCard().addAbility(new BlueManaAbility()); + + // {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 ability2 = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY), + new ManaCostsImpl<>("{2}{U}") + ); + ability2.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability2); } private SearchForAzcanta(final SearchForAzcanta card) { diff --git a/Mage.Sets/src/mage/cards/s/SearchForDagger.java b/Mage.Sets/src/mage/cards/s/SearchForDagger.java index 07812507446..1e7aa9d87d5 100644 --- a/Mage.Sets/src/mage/cards/s/SearchForDagger.java +++ b/Mage.Sets/src/mage/cards/s/SearchForDagger.java @@ -21,7 +21,7 @@ import java.util.UUID; public final class SearchForDagger extends CardImpl { private static final FilterCard filter = new FilterCreatureCard("a legendary creature card"); - private static final FilterPermanent filter2 = new FilterPermanent("you commander"); + private static final FilterPermanent filter2 = new FilterPermanent("your commander"); static { filter.add(SuperType.LEGENDARY.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/s/SearingBlood.java b/Mage.Sets/src/mage/cards/s/SearingBlood.java index dde6c05bf80..91fcf8785da 100644 --- a/Mage.Sets/src/mage/cards/s/SearingBlood.java +++ b/Mage.Sets/src/mage/cards/s/SearingBlood.java @@ -23,7 +23,7 @@ public final class SearingBlood extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( new WhenTargetDiesDelayedTriggeredAbility( - new DamageTargetEffect(3, true, "the creature's controller"), + new DamageTargetEffect(3).withTargetDescription("the creature's controller"), SetTargetPointer.PLAYER ) )); diff --git a/Mage.Sets/src/mage/cards/s/SeasonedCathar.java b/Mage.Sets/src/mage/cards/s/SeasonedCathar.java deleted file mode 100644 index 57397897f3d..00000000000 --- a/Mage.Sets/src/mage/cards/s/SeasonedCathar.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.keyword.LifelinkAbility; -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 SeasonedCathar extends CardImpl { - - public SeasonedCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.nightCard = true; - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - } - - private SeasonedCathar(final SeasonedCathar card) { - super(card); - } - - @Override - public SeasonedCathar copy() { - return new SeasonedCathar(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SecretTunnel.java b/Mage.Sets/src/mage/cards/s/SecretTunnel.java new file mode 100644 index 00000000000..8b36b7017ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SecretTunnel.java @@ -0,0 +1,93 @@ +package mage.cards.s; + +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.common.GreatestSharedCreatureTypeCount; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SecretTunnel extends CardImpl { + + public SecretTunnel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.CAVE); + + // This land can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {4}, {T}: Two target creatures you control that share a creature type can't be blocked this turn. + Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new SecretTunnelTarget()); + this.addAbility(ability); + } + + private SecretTunnel(final SecretTunnel card) { + super(card); + } + + @Override + public SecretTunnel copy() { + return new SecretTunnel(this); + } +} + +class SecretTunnelTarget extends TargetPermanent { + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creatures you control that share a creature type"); + + SecretTunnelTarget() { + super(2, 2, filter, false); + } + + private SecretTunnelTarget(final SecretTunnelTarget target) { + super(target); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + if (getTargets().isEmpty()) { + return true; + } + Permanent targetOne = game.getPermanent(getTargets().get(0)); + Permanent targetTwo = game.getPermanent(id); + if (targetOne == null || targetTwo == null) { + return false; + } + return targetOne.shareCreatureTypes(game, targetTwo); + } + + @Override + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return GreatestSharedCreatureTypeCount.getValue(sourceControllerId, source, game) >= 2; + } + + @Override + public SecretTunnelTarget copy() { + return new SecretTunnelTarget(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java index 5a5b24a3247..f8afb4c2a63 100644 --- a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java +++ b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java @@ -1,17 +1,14 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.Game; -import mage.watchers.common.SpellsCastWatcher; import java.util.UUID; @@ -30,8 +27,8 @@ public final class SeekerOfInsight extends CardImpl { // {T}: Draw a card, then discard a card. Activate this ability only if you've cast a noncreature spell this turn. this.addAbility(new ActivateIfConditionActivatedAbility( - new DrawDiscardControllerEffect(), new TapSourceCost(), SeekerOfInsightCondition.instance - )); + new DrawDiscardControllerEffect(), new TapSourceCost(), CastNoncreatureSpellThisTurnCondition.instance + ).addHint(CastNoncreatureSpellThisTurnCondition.getHint())); } private SeekerOfInsight(final SeekerOfInsight card) { @@ -43,22 +40,3 @@ public final class SeekerOfInsight extends CardImpl { return new SeekerOfInsight(this); } } - -enum SeekerOfInsightCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return game - .getState() - .getWatcher(SpellsCastWatcher.class) - .getSpellsCastThisTurn(source.getControllerId()) - .stream() - .anyMatch(spell -> !spell.isCreature(game)); - } - - @Override - public String toString() { - return "you've cast a noncreature spell this turn"; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SeiferBalambRival.java b/Mage.Sets/src/mage/cards/s/SeiferBalambRival.java new file mode 100644 index 00000000000..45f4d2e8741 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeiferBalambRival.java @@ -0,0 +1,102 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; +import mage.target.targetpointer.FixedTarget; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SeiferBalambRival extends CardImpl { + + public SeiferBalambRival(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Whenever you attack a player, goad target creature that player controls. + Ability ability = new AttacksPlayerWithCreaturesTriggeredAbility( + new GoadTargetEffect().setText("goad target creature that player controls"), SetTargetPointer.NONE + ); + ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); + this.addAbility(ability); + + // Whenever a creature attacking one of your opponents becomes blocked by two or more creatures, that attacking creature gains deathtouch until end of turn. + this.addAbility(new SeiferBalambRivalTriggeredAbility()); + } + + private SeiferBalambRival(final SeiferBalambRival card) { + super(card); + } + + @Override + public SeiferBalambRival copy() { + return new SeiferBalambRival(this); + } +} + +class SeiferBalambRivalTriggeredAbility extends TriggeredAbilityImpl { + + SeiferBalambRivalTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(DeathtouchAbility.getInstance()).setText("that attacking creature gains deathtouch until end of turn")); + this.setTriggerPhrase("Whenever a creature attacking one of your opponents becomes blocked by two or more creatures, "); + } + + private SeiferBalambRivalTriggeredAbility(final SeiferBalambRivalTriggeredAbility ability) { + super(ability); + } + + @Override + public SeiferBalambRivalTriggeredAbility copy() { + return new SeiferBalambRivalTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CREATURE_BLOCKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!game + .getOpponents(game.getCombat().getDefenderId(event.getTargetId())) + .contains(this.getControllerId()) + || game + .getCombat() + .findGroup(event.getTargetId()) + .getBlockers() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .filter(permanent -> permanent.isCreature(game)) + .count() < 2) { + return false; + } + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeismicSense.java b/Mage.Sets/src/mage/cards/s/SeismicSense.java new file mode 100644 index 00000000000..2c27cb23a7b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeismicSense.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.abilities.dynamicvalue.common.LandsYouControlCount; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SeismicSense extends CardImpl { + + public SeismicSense(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); + + this.subtype.add(SubType.LESSON); + + // Look at the top X cards of your library, where X is the number of lands you control. 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( + LandsYouControlCount.instance, 1, + StaticFilters.FILTER_CARD_CREATURE_OR_LAND, + PutCards.HAND, PutCards.BOTTOM_RANDOM + )); + this.getSpellAbility().addHint(LandsYouControlHint.instance); + } + + private SeismicSense(final SeismicSense card) { + super(card); + } + + @Override + public SeismicSense copy() { + return new SeismicSense(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeismicWave.java b/Mage.Sets/src/mage/cards/s/SeismicWave.java index ebc6f6a8e18..e3cf4e810a4 100644 --- a/Mage.Sets/src/mage/cards/s/SeismicWave.java +++ b/Mage.Sets/src/mage/cards/s/SeismicWave.java @@ -28,8 +28,8 @@ public final class SeismicWave extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Seismic Wave deals 2 damage to any target and 1 damage to each nonartifact creature target opponent controls. - this.getSpellAbility().addTarget(new TargetAnyTarget().withChooseHint("2 damage")); - this.getSpellAbility().addTarget(new TargetOpponent().withChooseHint("1 damage to each nonartifact creature target opponent controls")); + this.getSpellAbility().addTarget(new TargetAnyTarget().withChooseHint("to deal 2 damage")); + this.getSpellAbility().addTarget(new TargetOpponent().withChooseHint("1 damage to each nonartifact creature they control")); this.getSpellAbility().addEffect(new SeismicWaveEffect()); } @@ -51,7 +51,7 @@ class SeismicWaveEffect extends OneShotEffect { filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); } - public SeismicWaveEffect() { + SeismicWaveEffect() { super(Outcome.Damage); this.staticText = "{this} deals 2 damage to any target and 1 damage to each nonartifact creature target opponent controls"; } diff --git a/Mage.Sets/src/mage/cards/s/SelfDestruct.java b/Mage.Sets/src/mage/cards/s/SelfDestruct.java index 8e57a76ef4c..4d4fbb70754 100644 --- a/Mage.Sets/src/mage/cards/s/SelfDestruct.java +++ b/Mage.Sets/src/mage/cards/s/SelfDestruct.java @@ -89,7 +89,7 @@ class SelfDestructEffect extends OneShotEffect { if (player != null) { player.damage(power, creature.getId(), source, game); } - permanent.damage(power, permanent.getId(), source, game); + creature.damage(power, creature.getId(), source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SentinelTower.java b/Mage.Sets/src/mage/cards/s/SentinelTower.java index 3526e28c1ea..9609bb3b846 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelTower.java +++ b/Mage.Sets/src/mage/cards/s/SentinelTower.java @@ -5,7 +5,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.ValueHint; @@ -50,7 +50,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { private String damageInfo; SentinelTowerTriggeredAbility() { - super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); + super(new DamageTargetEffect(SavedDamageValue.MUCH), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); this.addTarget(new TargetAnyTarget()); this.addHint(new ValueHint("There were cast instant and sorcery this turn", SentinelTowerSpellsCastValue.instance)); this.damageInfo = null; @@ -87,12 +87,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { } } damageInfo = " (" + damageToDeal + " damage)"; - for (Effect effect : this.getEffects()) { - if (effect instanceof DamageTargetEffect) { - ((DamageTargetEffect) effect).setAmount(StaticValue.get(damageToDeal)); - return true; - } - } + this.getEffects().setValue("damage", damageToDeal); } return false; } @@ -166,4 +161,4 @@ enum SentinelTowerSpellsCastValue implements DynamicValue { public String getMessage() { return "There was an instant or sorcery spell in this turn"; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java b/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java index b0e3b72d950..f105ff526dc 100644 --- a/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java +++ b/Mage.Sets/src/mage/cards/s/SephirothFabledSOLDIER.java @@ -1,47 +1,53 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.*; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.emblems.SephirothOneWingedAngelEmblem; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.target.common.TargetSacrifice; import mage.watchers.common.AbilityResolvedWatcher; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class SephirothFabledSOLDIER extends CardImpl { +public final class SephirothFabledSOLDIER extends TransformingDoubleFacedCard { public SephirothFabledSOLDIER(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.SOLDIER}, "{2}{B}", + "Sephiroth, One-Winged Angel", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL, SubType.NIGHTMARE, SubType.AVATAR}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.s.SephirothOneWingedAngel.class; + // Sephiroth, Fabled SOLDIER + this.getLeftHalfCard().setPT(3, 3); // Whenever Sephiroth enters or attacks, you may sacrifice another creature. If you do, draw a card. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DoIfCostPaid( + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DoIfCostPaid( new DrawCardSourceControllerEffect(1), new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE) ))); // Whenever another creature dies, target opponent loses 1 life and you gain 1 life. If this is the fourth time this ability has resolved this turn, transform Sephiroth. - this.addAbility(new TransformAbility()); Ability ability = new DiesCreatureTriggeredAbility( new LoseLifeTargetEffect(1), false, StaticFilters.FILTER_ANOTHER_CREATURE @@ -49,7 +55,21 @@ public final class SephirothFabledSOLDIER extends CardImpl { ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addEffect(new IfAbilityHasResolvedXTimesEffect(4, new TransformSourceEffect())); ability.addTarget(new TargetOpponent()); - this.addAbility(ability, new AbilityResolvedWatcher()); + ability.addWatcher(new AbilityResolvedWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Sephiroth, One-Winged Angel + this.getRightHalfCard().setPT(5, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Super Nova -- As this creature transforms into Sephiroth, One-Winged Angel, you get an emblem with "Whenever a creature dies, target opponent loses 1 life and you gain 1 life." + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SephirothOneWingedAngelEmblemEffect()).withFlavorWord("Super Nova")); + + // Whenever Sephiroth attacks, you may sacrifice any number of other creatures. If you do, draw that many cards. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new SephirothOneWingedAngelSacrificeEffect())); + } private SephirothFabledSOLDIER(final SephirothFabledSOLDIER card) { @@ -61,3 +81,80 @@ public final class SephirothFabledSOLDIER extends CardImpl { return new SephirothFabledSOLDIER(this); } } + +class SephirothOneWingedAngelEmblemEffect extends ReplacementEffectImpl { + + SephirothOneWingedAngelEmblemEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "as this creature transforms into {this}, " + + "you get an emblem with \"Whenever a creature dies, target opponent loses 1 life and you gain 1 life.\""; + } + + private SephirothOneWingedAngelEmblemEffect(final SephirothOneWingedAngelEmblemEffect effect) { + super(effect); + } + + @Override + public SephirothOneWingedAngelEmblemEffect copy() { + return new SephirothOneWingedAngelEmblemEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Optional.ofNullable(source.getSourceObject(game)) + .ifPresent(obj -> game.addEmblem(new SephirothOneWingedAngelEmblem(), obj, source)); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TRANSFORMING; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getSourceId().equals(event.getTargetId()) + && source.getSourcePermanentIfItStillExists(game) != null; + } +} + +class SephirothOneWingedAngelSacrificeEffect extends OneShotEffect { + + SephirothOneWingedAngelSacrificeEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice any number of other creatures. If you do, draw that many cards"; + } + + private SephirothOneWingedAngelSacrificeEffect(final SephirothOneWingedAngelSacrificeEffect effect) { + super(effect); + } + + @Override + public SephirothOneWingedAngelSacrificeEffect copy() { + return new SephirothOneWingedAngelSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetSacrifice target = new TargetSacrifice( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_ANOTHER_CREATURE + ); + player.choose(outcome, target, source, game); + int count = 0; + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null && permanent.sacrifice(source, game)) { + count++; + } + } + if (count < 1) { + return false; + } + player.drawCards(count, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SephirothOneWingedAngel.java b/Mage.Sets/src/mage/cards/s/SephirothOneWingedAngel.java deleted file mode 100644 index 7b4cb758e14..00000000000 --- a/Mage.Sets/src/mage/cards/s/SephirothOneWingedAngel.java +++ /dev/null @@ -1,136 +0,0 @@ -package mage.cards.s; - -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.ReplacementEffectImpl; -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.command.emblems.SephirothOneWingedAngelEmblem; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetSacrifice; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SephirothOneWingedAngel extends CardImpl { - - public SephirothOneWingedAngel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ANGEL); - this.subtype.add(SubType.NIGHTMARE); - this.subtype.add(SubType.AVATAR); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setBlack(true); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Super Nova -- As this creature transforms into Sephiroth, One-Winged Angel, you get an emblem with "Whenever a creature dies, target opponent loses 1 life and you gain 1 life." - this.addAbility(new SimpleStaticAbility(new SephirothOneWingedAngelEmblemEffect()).withFlavorWord("Super Nova")); - - // Whenever Sephiroth attacks, you may sacrifice any number of other creatures. If you do, draw that many cards. - this.addAbility(new AttacksTriggeredAbility(new SephirothOneWingedAngelSacrificeEffect())); - } - - private SephirothOneWingedAngel(final SephirothOneWingedAngel card) { - super(card); - } - - @Override - public SephirothOneWingedAngel copy() { - return new SephirothOneWingedAngel(this); - } -} - -class SephirothOneWingedAngelEmblemEffect extends ReplacementEffectImpl { - - SephirothOneWingedAngelEmblemEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "as this creature transforms into {this}, " + - "you get an emblem with \"Whenever a creature dies, target opponent loses 1 life and you gain 1 life.\""; - } - - private SephirothOneWingedAngelEmblemEffect(final SephirothOneWingedAngelEmblemEffect effect) { - super(effect); - } - - @Override - public SephirothOneWingedAngelEmblemEffect copy() { - return new SephirothOneWingedAngelEmblemEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Optional.ofNullable(source.getSourceObject(game)) - .ifPresent(obj -> game.addEmblem(new SephirothOneWingedAngelEmblem(), obj, source)); - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.TRANSFORMING; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return source.getSourceId().equals(event.getTargetId()) - && source.getSourcePermanentIfItStillExists(game) != null; - } -} - -class SephirothOneWingedAngelSacrificeEffect extends OneShotEffect { - - SephirothOneWingedAngelSacrificeEffect() { - super(Outcome.Benefit); - staticText = "you may sacrifice any number of other creatures. If you do, draw that many cards"; - } - - private SephirothOneWingedAngelSacrificeEffect(final SephirothOneWingedAngelSacrificeEffect effect) { - super(effect); - } - - @Override - public SephirothOneWingedAngelSacrificeEffect copy() { - return new SephirothOneWingedAngelSacrificeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetSacrifice target = new TargetSacrifice( - 0, Integer.MAX_VALUE, StaticFilters.FILTER_ANOTHER_CREATURE - ); - player.choose(outcome, target, source, game); - int count = 0; - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null && permanent.sacrifice(source, game)) { - count++; - } - } - if (count < 1) { - return false; - } - player.drawCards(count, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SerahFarron.java b/Mage.Sets/src/mage/cards/s/SerahFarron.java index 5e77209c353..2c504648e74 100644 --- a/Mage.Sets/src/mage/cards/s/SerahFarron.java +++ b/Mage.Sets/src/mage/cards/s/SerahFarron.java @@ -1,26 +1,23 @@ package mage.cards.s; -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.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueConditionHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; 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.constants.WatcherScope; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.ObjectSourcePlayer; @@ -38,7 +35,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SerahFarron extends CardImpl { +public final class SerahFarron extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCreatureCard("the first legendary creature spell you cast each turn"); @@ -59,23 +56,32 @@ public final class SerahFarron extends CardImpl { ); public SerahFarron(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CITIZEN}, "{1}{G}{W}", + "Crystallized Serah", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "WG"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CITIZEN); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.c.CrystallizedSerah.class; + // Serah Farron + this.getLeftHalfCard().setPT(2, 2); // The first legendary creature spell you cast each turn costs {2} less to cast. - this.addAbility(makeAbility(), new SerahFarronWatcher()); + Ability ability = new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2)); + ability.addWatcher(new SerahFarronWatcher()); + this.getLeftHalfCard().addAbility(ability); // At the beginning of combat on your turn, if you control two or more other legendary creatures, you may transform Serah Farron. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfCombatTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfCombatTriggeredAbility( new TransformSourceEffect(), true ).withInterveningIf(condition).addHint(hint)); + + // Crystallized Serah + // The first legendary creature spell you cast each turn costs {2} less to cast. + this.getRightHalfCard().addAbility(ability.copy()); + + // Legendary creatures you control get +2/+2. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 2, 2, Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURES_LEGENDARY + ))); } private SerahFarron(final SerahFarron card) { @@ -86,11 +92,6 @@ public final class SerahFarron extends CardImpl { public SerahFarron copy() { return new SerahFarron(this); } - - public static Ability makeAbility() { - return new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2)); - } - } enum SerahFarronPredicate implements ObjectSourcePlayerPredicate { diff --git a/Mage.Sets/src/mage/cards/s/SeraphOfNewCapenna.java b/Mage.Sets/src/mage/cards/s/SeraphOfNewCapenna.java index 4fbe986ba2a..a5a726156d9 100644 --- a/Mage.Sets/src/mage/cards/s/SeraphOfNewCapenna.java +++ b/Mage.Sets/src/mage/cards/s/SeraphOfNewCapenna.java @@ -1,38 +1,54 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 SeraphOfNewCapenna extends CardImpl { +public final class SeraphOfNewCapenna extends TransformingDoubleFacedCard { public SeraphOfNewCapenna(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL, SubType.SOLDIER}, "{2}{W}", + "Seraph of New Phyrexia", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ANGEL}, "WB" + ); - this.subtype.add(SubType.ANGEL); - this.subtype.add(SubType.SOLDIER); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.s.SeraphOfNewPhyrexia.class; + // Seraph of New Capenna + this.getLeftHalfCard().setPT(2, 2); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // {4}{B/P}: Transform Seraph of New Capenna. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{B/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{B/P}"))); + + // Seraph of New Phyrexia + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever Seraph of New Phyrexia attacks, you may sacrifice another creature or artifact. If you do, Seraph of New Phyrexia gets +2/+1 until end of turn. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new BoostSourceEffect(2, 1, Duration.EndOfTurn), + new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT) + ))); } private SeraphOfNewCapenna(final SeraphOfNewCapenna card) { diff --git a/Mage.Sets/src/mage/cards/s/SeraphOfNewPhyrexia.java b/Mage.Sets/src/mage/cards/s/SeraphOfNewPhyrexia.java deleted file mode 100644 index 04a2cc66784..00000000000 --- a/Mage.Sets/src/mage/cards/s/SeraphOfNewPhyrexia.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.common.DoIfCostPaid; -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.Duration; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SeraphOfNewPhyrexia extends CardImpl { - - public SeraphOfNewPhyrexia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Whenever Seraph of New Phyrexia attacks, you may sacrifice another creature or artifact. If you do, Seraph of New Phyrexia gets +2/+1 until end of turn. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( - new BoostSourceEffect(2, 1, Duration.EndOfTurn), - new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE_OR_ARTIFACT) - ))); - } - - private SeraphOfNewPhyrexia(final SeraphOfNewPhyrexia card) { - super(card); - } - - @Override - public SeraphOfNewPhyrexia copy() { - return new SeraphOfNewPhyrexia(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SerpentsPass.java b/Mage.Sets/src/mage/cards/s/SerpentsPass.java new file mode 100644 index 00000000000..86def0461ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SerpentsPass.java @@ -0,0 +1,48 @@ +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.GenericManaCost; +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 SerpentsPass extends CardImpl { + + public SerpentsPass(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {B}. + this.addAbility(new BlueManaAbility()); + this.addAbility(new BlackManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private SerpentsPass(final SerpentsPass card) { + super(card); + } + + @Override + public SerpentsPass copy() { + return new SerpentsPass(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerraFaithkeeper.java b/Mage.Sets/src/mage/cards/s/SerraFaithkeeper.java deleted file mode 100644 index 21a7c081401..00000000000 --- a/Mage.Sets/src/mage/cards/s/SerraFaithkeeper.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -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.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SerraFaithkeeper extends CardImpl { - - public SerraFaithkeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ANGEL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setWhite(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - } - - private SerraFaithkeeper(final SerraFaithkeeper card) { - super(card); - } - - @Override - public SerraFaithkeeper copy() { - return new SerraFaithkeeper(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SeshirosLivingLegacy.java b/Mage.Sets/src/mage/cards/s/SeshirosLivingLegacy.java deleted file mode 100644 index 61ed396df36..00000000000 --- a/Mage.Sets/src/mage/cards/s/SeshirosLivingLegacy.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.keyword.HasteAbility; -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 SeshirosLivingLegacy extends CardImpl { - - public SeshirosLivingLegacy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SNAKE); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - this.color.setGreen(true); - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - } - - private SeshirosLivingLegacy(final SeshirosLivingLegacy card) { - super(card); - } - - @Override - public SeshirosLivingLegacy copy() { - return new SeshirosLivingLegacy(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShadowGuildmage.java b/Mage.Sets/src/mage/cards/s/ShadowGuildmage.java index af5c2d262a4..eafc596a173 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowGuildmage.java +++ b/Mage.Sets/src/mage/cards/s/ShadowGuildmage.java @@ -1,21 +1,20 @@ 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.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** * @@ -37,9 +36,8 @@ public final class ShadowGuildmage extends CardImpl { this.addAbility(ability); // {R}, {tap}: Shadow Guildmage deals 1 damage to any target and 1 damage to you. - ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{R}")); + ability = new SimpleActivatedAbility(new DamageTargetAndYouEffect(1, 1), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new DamageControllerEffect(1).setText("and 1 damage to you")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java b/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java index 2670cc3f137..8c4feb6466d 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java +++ b/Mage.Sets/src/mage/cards/s/ShadowInTheWarp.java @@ -14,7 +14,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Controllable; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; @@ -22,6 +21,7 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; import mage.watchers.common.SpellsCastWatcher; + import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -108,8 +108,8 @@ class FirstCastCreatureSpellPredicate implements ObjectSourcePlayerPredicate("{B}") - ); - ability.addCost(new TapSourceCost()); - ability.addCost(new RemoveCountersSourceCost(CounterType.DREAD.createInstance())); - ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); - this.addAbility(ability); - } - - private ShadowsLair(final ShadowsLair card) { - super(card); - } - - @Override - public ShadowsLair copy() { - return new ShadowsLair(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShadyTraveler.java b/Mage.Sets/src/mage/cards/s/ShadyTraveler.java index a7c56fa4541..d6b8b7f501b 100644 --- a/Mage.Sets/src/mage/cards/s/ShadyTraveler.java +++ b/Mage.Sets/src/mage/cards/s/ShadyTraveler.java @@ -1,10 +1,10 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +13,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ShadyTraveler extends CardImpl { +public final class ShadyTraveler extends TransformingDoubleFacedCard { public ShadyTraveler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{B}", + "Stalking Predator", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.s.StalkingPredator.class; + // Shady Traveler + this.getLeftHalfCard().setPT(2, 3); // Menace - this.addAbility(new MenaceAbility()); + this.getLeftHalfCard().addAbility(new MenaceAbility()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Stalking Predator + this.getRightHalfCard().setPT(4, 4); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private ShadyTraveler(final ShadyTraveler card) { diff --git a/Mage.Sets/src/mage/cards/s/SharedRoots.java b/Mage.Sets/src/mage/cards/s/SharedRoots.java new file mode 100644 index 00000000000..2680eed5bad --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SharedRoots.java @@ -0,0 +1,37 @@ +package mage.cards.s; + +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.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SharedRoots extends CardImpl { + + public SharedRoots(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + this.subtype.add(SubType.LESSON); + + // Search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + )); + } + + private SharedRoots(final SharedRoots card) { + super(card); + } + + @Override + public SharedRoots copy() { + return new SharedRoots(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShayCormac.java b/Mage.Sets/src/mage/cards/s/ShayCormac.java index 5878a3d67ff..1e125076a7d 100644 --- a/Mage.Sets/src/mage/cards/s/ShayCormac.java +++ b/Mage.Sets/src/mage/cards/s/ShayCormac.java @@ -58,7 +58,7 @@ public final class ShayCormac extends CardImpl { // Whenever a creature with a bounty counter on it dies, put two +1/+1 counters on Shay Cormac. this.addAbility(new DiesCreatureTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, filter2 + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), false, filter2 )); } diff --git a/Mage.Sets/src/mage/cards/s/Sheoldred.java b/Mage.Sets/src/mage/cards/s/Sheoldred.java index 49f1aad0ef4..b8c6397069a 100644 --- a/Mage.Sets/src/mage/cards/s/Sheoldred.java +++ b/Mage.Sets/src/mage/cards/s/Sheoldred.java @@ -1,27 +1,40 @@ package mage.cards.s; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.condition.common.CardsInOpponentGraveyardCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; -import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.targetadjustment.ForEachPlayerTargetsAdjuster; +import mage.target.targetpointer.EachTargetPointer; +import java.util.Collection; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 */ -public final class Sheoldred extends CardImpl { +public final class Sheoldred extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("nontoken creature or planeswalker"); @@ -31,27 +44,56 @@ public final class Sheoldred extends CardImpl { } public Sheoldred(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{3}{B}{B}", + "The True Scriptures", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.PRAETOR); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.t.TheTrueScriptures.class; + // Sheoldred + this.getLeftHalfCard().setPT(4, 5); // Menace - this.addAbility(new MenaceAbility(false)); + this.getLeftHalfCard().addAbility(new MenaceAbility(false)); // When Sheoldred enters the battlefield, each opponent sacrifices a nontoken creature or planeswalker. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(filter))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeOpponentsEffect(filter))); // {4}{B}: Exile Sheoldred, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery and only if an opponent has eight or more cards in their graveyard. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{B}"), CardsInOpponentGraveyardCondition.EIGHT ).setTiming(TimingRule.SORCERY).addHint(CardsInOpponentGraveyardCondition.EIGHT.getHint())); + + // The True Scriptures + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- For each opponent, destroy up to one target creature or planeswalker that player controls. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, false, + ability -> { + ability.addEffect(new DestroyTargetEffect().setTargetPointer(new EachTargetPointer()) + .setText("for each opponent, destroy up to one target creature or planeswalker that player controls")); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1)); + ability.setTargetAdjuster(new ForEachPlayerTargetsAdjuster(false, true)); + } + ); + + // II -- Each opponent discards three cards, then mills three cards. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_II, + new DiscardEachPlayerEffect(StaticValue.get(3), false, TargetController.OPPONENT), + new MillCardsEachPlayerEffect(3, TargetController.OPPONENT).setText(", then mills three cards") + ); + + // III -- Put all creature cards from all graveyards onto the battlefield under your control. Exile The True Scriptures, then return it to the battlefield. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new SheoldredTrueScripturesEffect(), + new ExileSourceAndReturnFaceUpEffect() + ); + this.getRightHalfCard().addAbility(sagaAbility); } private Sheoldred(final Sheoldred card) { @@ -63,3 +105,39 @@ public final class Sheoldred extends CardImpl { return new Sheoldred(this); } } + +class SheoldredTrueScripturesEffect extends OneShotEffect { + + SheoldredTrueScripturesEffect() { + super(Outcome.Benefit); + staticText = "put all creature cards from all graveyards onto the battlefield under your control"; + } + + private SheoldredTrueScripturesEffect(final SheoldredTrueScripturesEffect effect) { + super(effect); + } + + @Override + public SheoldredTrueScripturesEffect copy() { + return new SheoldredTrueScripturesEffect(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 + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(gy -> gy.getCards(StaticFilters.FILTER_CARD_CREATURE, game)) + .flatMap(Collection::stream) + .collect(Collectors.toList())); + return player.moveCards(cards, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java b/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java index 3930bb4f6ec..e8442b280b1 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java +++ b/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java @@ -9,12 +9,12 @@ import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.EquipAbility; 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.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import java.util.UUID; @@ -50,7 +50,7 @@ public final class ShieldOfTheAvatar extends CardImpl { class ShieldOfTheAvatarPreventionEffect extends PreventionEffectImpl { ShieldOfTheAvatarPreventionEffect() { - super(Duration.WhileOnBattlefield); + super(Duration.WhileOnBattlefield, 0, false, false); this.staticText = "If a source would deal damage to equipped creature, prevent X of that damage, where X is the number of creatures you control."; } @@ -65,26 +65,8 @@ class ShieldOfTheAvatarPreventionEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - boolean result = false; - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null) { - int numberOfCreaturesControlled = CreaturesYouControlCount.PLURAL.calculate(game, source, this); - int toPrevent = Math.min(numberOfCreaturesControlled, event.getAmount()); - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent, ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - if (event.getAmount() >= toPrevent) { - event.setAmount(event.getAmount() - toPrevent); - } else { - event.setAmount(0); - result = true; - } - if (toPrevent > 0) { - game.informPlayers("Shield of the Avatar " + "prevented " + toPrevent + " damage to " + game.getPermanent(equipment.getAttachedTo()).getName()); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent)); - } - } - } - return result; + amountToPrevent = CreaturesYouControlCount.PLURAL.calculate(game, source, this); + return super.replaceEvent(event, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java index 5292792f6ef..5fcfe39ab60 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java +++ b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,17 +12,18 @@ 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.Zone; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetSource; -import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** * * @author L_J @@ -86,12 +86,6 @@ class ShieldmageAdvocateEffect extends PreventionEffectImpl { this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - preventDamageAction(event, source, game); - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game)) { diff --git a/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java b/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java deleted file mode 100644 index 712dfdb3e7d..00000000000 --- a/Mage.Sets/src/mage/cards/s/ShinryuTranscendentRival.java +++ /dev/null @@ -1,137 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.WinGameSourceControllerEffect; -import mage.abilities.keyword.FlyingAbility; -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.Player; -import mage.target.TargetPlayer; -import mage.target.common.TargetOpponent; -import mage.util.CardUtil; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ShinryuTranscendentRival extends CardImpl { - - public ShinryuTranscendentRival(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - this.color.setBlack(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // As this creature transforms into Shinryu, choose an opponent. - this.addAbility(new SimpleStaticAbility(new ShinryuTranscendentRivalEffect())); - - // Burning Chains -- When the chosen player loses the game, you win the game. - this.addAbility(new ShinryuTranscendentRivalTriggeredAbility()); - } - - private ShinryuTranscendentRival(final ShinryuTranscendentRival card) { - super(card); - } - - @Override - public ShinryuTranscendentRival copy() { - return new ShinryuTranscendentRival(this); - } -} - -class ShinryuTranscendentRivalEffect extends ReplacementEffectImpl { - - ShinryuTranscendentRivalEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "as this creature transforms into {this}, choose an opponent"; - } - - private ShinryuTranscendentRivalEffect(final ShinryuTranscendentRivalEffect effect) { - super(effect); - } - - @Override - public ShinryuTranscendentRivalEffect copy() { - return new ShinryuTranscendentRivalEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller == null || permanent == null) { - return false; - } - TargetPlayer target = new TargetOpponent(true); - controller.choose(outcome, target, source, game); - Player opponent = game.getPlayer(target.getFirstTarget()); - if (opponent == null) { - return false; - } - game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); - game.getState().setValue(permanent.getId() + "_" + permanent.getZoneChangeCounter(game) + "_opponent", opponent.getId()); - permanent.addInfo("chosen opponent", CardUtil.addToolTipMarkTags("Chosen Opponent " + opponent.getLogName()), game); - return false; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.TRANSFORMING; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return source.getSourceId().equals(event.getTargetId()) - && source.getSourcePermanentIfItStillExists(game) != null; - } -} - -class ShinryuTranscendentRivalTriggeredAbility extends TriggeredAbilityImpl { - - ShinryuTranscendentRivalTriggeredAbility() { - super(Zone.BATTLEFIELD, new WinGameSourceControllerEffect()); - this.setTriggerPhrase("When the chosen player loses the game, "); - this.withFlavorWord("Burning Chains"); - } - - private ShinryuTranscendentRivalTriggeredAbility(final ShinryuTranscendentRivalTriggeredAbility ability) { - super(ability); - } - - @Override - public ShinryuTranscendentRivalTriggeredAbility copy() { - return new ShinryuTranscendentRivalTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.LOST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - int zcc = game.getState().getZoneChangeCounter(this.getSourceId()); - return Optional - .of(this.getSourceId() + "_" + zcc + "_opponent") - .map(game.getState()::getValue) - .map(event.getPlayerId()::equals) - .orElse(false); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShivaWardenOfIce.java b/Mage.Sets/src/mage/cards/s/ShivaWardenOfIce.java deleted file mode 100644 index cf667f30444..00000000000 --- a/Mage.Sets/src/mage/cards/s/ShivaWardenOfIce.java +++ /dev/null @@ -1,66 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.TapAllEffect; -import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterLandPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ShivaWardenOfIce extends CardImpl { - - private static final FilterPermanent filter = new FilterLandPermanent("lands your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - - public ShivaWardenOfIce(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.nightCard = true; - this.color.setBlue(true); - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Mesmerize -- Target creature can't be blocked this turn. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, ability -> { - ability.addEffect(new CantBeBlockedTargetEffect(Duration.EndOfTurn)); - ability.addTarget(new TargetCreaturePermanent()); - ability.withFlavorWord("Mesmerize"); - }); - - // III -- Cold Snap -- Tap all lands your opponents control. Exile Shiva, then return it to the battlefield. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { - ability.addEffect(new TapAllEffect(filter)); - ability.addEffect(new ExileSourceAndReturnFaceUpEffect()); - ability.withFlavorWord("Cold Snap"); - }); - this.addAbility(sagaAbility); - } - - private ShivaWardenOfIce(final ShivaWardenOfIce card) { - super(card); - } - - @Override - public ShivaWardenOfIce copy() { - return new ShivaWardenOfIce(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java b/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java index 661ecfe7032..d4a1b2c57d1 100644 --- a/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java +++ b/Mage.Sets/src/mage/cards/s/ShockerUnshakable.java @@ -6,8 +6,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; @@ -42,8 +41,7 @@ public final class ShockerUnshakable extends CardImpl { ))); // Vibro-Shock Gauntlets -- When Shocker enters, he deals 2 damage to target creature and 2 damage to that creature's controller. - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "he")); - ability.addEffect(new DamageTargetControllerEffect(2).setText("and 2 damage to that creature's controller")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetAndTargetControllerEffect(2, 2)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability.withFlavorWord("Vibro-Shock Gauntlets")); } diff --git a/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java b/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java index 6a4bcfce98b..3fbd5358212 100644 --- a/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java +++ b/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java @@ -41,9 +41,6 @@ public final class ShorikaiGenesisEngine extends CardImpl { // Crew 8 this.addAbility(new CrewAbility(8)); - - // Shorikai, Genesis Engine can be your commander. - this.addAbility(CanBeYourCommanderAbility.getInstance()); } private ShorikaiGenesisEngine(final ShorikaiGenesisEngine card) { diff --git a/Mage.Sets/src/mage/cards/s/ShowerOfSparks.java b/Mage.Sets/src/mage/cards/s/ShowerOfSparks.java index db144515b38..8d13d17e372 100644 --- a/Mage.Sets/src/mage/cards/s/ShowerOfSparks.java +++ b/Mage.Sets/src/mage/cards/s/ShowerOfSparks.java @@ -1,13 +1,14 @@ package mage.cards.s; -import java.util.UUID; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** * * @author LevelX2 @@ -17,10 +18,10 @@ public final class ShowerOfSparks extends CardImpl { public ShowerOfSparks(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); - // Shower of sparks deals 1 damage to target creature and 1 damage to target player. - this.getSpellAbility().addEffect(new DamageTargetEffect(1, true, "target creature and 1 damage to target player or planeswalker")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); + // Shower of Sparks deals 1 damage to target creature and 1 damage to target player or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(1, 1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker().setTargetTag(2)); } private ShowerOfSparks(final ShowerOfSparks card) { diff --git a/Mage.Sets/src/mage/cards/s/ShriekTreblemaker.java b/Mage.Sets/src/mage/cards/s/ShriekTreblemaker.java index e90bf9be2ef..32ab6ffd1fc 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekTreblemaker.java +++ b/Mage.Sets/src/mage/cards/s/ShriekTreblemaker.java @@ -41,7 +41,7 @@ public final class ShriekTreblemaker extends CardImpl { // Sonic Blast -- Whenever a creature an opponent controls dies, Shriek deals 1 damage to that player. this.addAbility(new DiesCreatureTriggeredAbility( Zone.BATTLEFIELD, - new DamageTargetEffect(1, true, "that player"), + new DamageTargetEffect(1).withTargetDescription("that player"), false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE, SetTargetPointer.PLAYER) diff --git a/Mage.Sets/src/mage/cards/s/ShrillHowler.java b/Mage.Sets/src/mage/cards/s/ShrillHowler.java index 40e9b05ce39..4f7742553d9 100644 --- a/Mage.Sets/src/mage/cards/s/ShrillHowler.java +++ b/Mage.Sets/src/mage/cards/s/ShrillHowler.java @@ -1,42 +1,49 @@ - package mage.cards.s; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesWithLessPowerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.game.permanent.token.EldraziHorrorToken; + +import java.util.UUID; /** * @author LevelX2 */ -public final class ShrillHowler extends CardImpl { +public final class ShrillHowler extends TransformingDoubleFacedCard { public ShrillHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{2}{G}", + "Howling Chorus", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, "" + ); - this.secondSideCardClazz = mage.cards.h.HowlingChorus.class; + // Shrill Howler + this.getLeftHalfCard().setPT(3, 1); // Creatures with power less than Shrill Howler's power can't block it. - this.addAbility(new SimpleStaticAbility(new CantBeBlockedByCreaturesWithLessPowerEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CantBeBlockedByCreaturesWithLessPowerEffect())); // {5}{G}: Transform Shrill Howler. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}"))); + // Howling Chorus + this.getRightHalfCard().setPT(3, 5); + + // Creatures with power less than Howling Chorus's power can't block it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CantBeBlockedByCreaturesWithLessPowerEffect())); + + // Whenever Howling Chorus deals combat damage to a player, create a 3/2 colorless Eldrazi Horror creature token. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect(new EldraziHorrorToken()), false)); } private ShrillHowler(final ShrillHowler card) { diff --git a/Mage.Sets/src/mage/cards/s/SidequestCardCollection.java b/Mage.Sets/src/mage/cards/s/SidequestCardCollection.java index 16874c1afbc..36e79f2e98a 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestCardCollection.java +++ b/Mage.Sets/src/mage/cards/s/SidequestCardCollection.java @@ -5,32 +5,45 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import java.util.UUID; /** * @author TheElk801 */ -public final class SidequestCardCollection extends CardImpl { +public final class SidequestCardCollection extends TransformingDoubleFacedCard { private static final Condition condition = new CardsInControllerGraveyardCondition(8); public SidequestCardCollection(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); - - this.secondSideCardClazz = mage.cards.m.MagickedCard.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{U}", + "Magicked Card", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "U" + ); + // Sidequest: Card Collection // When this enchantment enters, draw three cards, then discard two cards. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(3, 2))); // At the beginning of your end step, if eight or more cards are in your graveyard, transform this enchantment. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()).withInterveningIf(condition)); + + // Magicked Card + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private SidequestCardCollection(final SidequestCardCollection card) { diff --git a/Mage.Sets/src/mage/cards/s/SidequestCatchAFish.java b/Mage.Sets/src/mage/cards/s/SidequestCatchAFish.java index a8c3b53caec..44872adf6b4 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestCatchAFish.java +++ b/Mage.Sets/src/mage/cards/s/SidequestCatchAFish.java @@ -1,36 +1,58 @@ package mage.cards.s; -import java.util.UUID; - 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.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.mana.WhiteManaAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; 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.token.FoodToken; import mage.players.Player; +import java.util.UUID; + /** * @author balazskristof */ -public final class SidequestCatchAFish extends CardImpl { +public final class SidequestCatchAFish extends TransformingDoubleFacedCard { public SidequestCatchAFish(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); - - this.secondSideCardClazz = mage.cards.c.CookingCampsite.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{W}", + "Cooking Campsite", + new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Sidequest: Catch a Fish // At the beginning of your upkeep, look at the top card of your library. If it's an artifact or creature card, you may reveal it and put it into your hand. If you put a card into your hand this way, create a Food token and transform this enchantment. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SidequestCatchAFishEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new SidequestCatchAFishEffect())); + + // Cooking Campsite + // {T}: Add {W}. + this.getRightHalfCard().addAbility(new WhiteManaAbility()); + + // {3}, {T}, Sacrifice an artifact: Put a +1/+1 counter on each creature you control. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE), new ManaCostsImpl<>("{3}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_AN)); + this.getRightHalfCard().addAbility(ability); } private SidequestCatchAFish(final SidequestCatchAFish card) { @@ -48,8 +70,8 @@ class SidequestCatchAFishEffect extends OneShotEffect { SidequestCatchAFishEffect() { super(Outcome.Benefit); staticText = "look at the top card of your library. " + - "If it's an artifact or creature card, you may reveal it and put it into your hand. " + - "If you put a card into your hand this way, create a Food token and transform this enchantment."; + "If it's an artifact or creature card, you may reveal it and put it into your hand. " + + "If you put a card into your hand this way, create a Food token and transform this enchantment."; } private SidequestCatchAFishEffect(final SidequestCatchAFishEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SidequestHuntTheMark.java b/Mage.Sets/src/mage/cards/s/SidequestHuntTheMark.java index 4b1ce5df4a5..78b97087cb3 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestHuntTheMark.java +++ b/Mage.Sets/src/mage/cards/s/SidequestHuntTheMark.java @@ -2,25 +2,30 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -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.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; 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; @@ -35,7 +40,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SidequestHuntTheMark extends CardImpl { +public final class SidequestHuntTheMark extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledPermanent(SubType.TREASURE), ComparisonType.MORE_THAN, 2 @@ -44,25 +49,51 @@ public final class SidequestHuntTheMark extends CardImpl { "Treasures you control", new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.TREASURE)) ); + private static final FilterPermanent ySacFilter = new FilterPermanent("another creature or artifact"); + + static { + ySacFilter.add(AnotherPredicate.instance); + ySacFilter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ARTIFACT.getPredicate() + )); + } + public SidequestHuntTheMark(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); - - this.secondSideCardClazz = mage.cards.y.YiazmatUltimateMark.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{B}{B}", + "Yiazmat, Ultimate Mark", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRAGON}, "B" + ); + // Sidequest: Hunt the Mark // When this enchantment enters, destroy up to one target creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetCreaturePermanent(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your end step, if a creature died under an opponent's control this turn, create a Treasure token. Then if you control three or more Treasures, transform this enchantment. - this.addAbility(new TransformAbility()); ability = new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new TreasureToken())) .withInterveningIf(SidequestHuntTheMarkCondition.instance); ability.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), condition, "Then if you control three or more Treasures, transform {this}" )); - this.addAbility(ability.addHint(hint).addHint(SidequestHuntTheMarkCondition.getHint()), new SidequestHuntTheMarkWatcher()); + ability.addHint(hint) + .addHint(SidequestHuntTheMarkCondition.getHint()); + ability.addWatcher(new SidequestHuntTheMarkWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Yiazmat, Ultimate Mark + this.getRightHalfCard().setPT(5, 6); + + // {1}{B}, Sacrifice another creature or artifact: Yiazmat gains indestructible until end of turn. Tap it. + Ability yAbility = new SimpleActivatedAbility( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}") + ); + yAbility.addCost(new SacrificeTargetCost(ySacFilter)); + yAbility.addEffect(new TapSourceEffect().setText("tap it")); + this.getRightHalfCard().addAbility(yAbility); } private SidequestHuntTheMark(final SidequestHuntTheMark card) { @@ -120,10 +151,10 @@ class SidequestHuntTheMarkWatcher extends Watcher { } static boolean checkPlayer(Game game, Ability source) { - return game + game .getState() - .getWatcher(SidequestHuntTheMarkWatcher.class) - .set + .getWatcher(SidequestHuntTheMarkWatcher.class); + return set .contains(source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java b/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java index 8720da23746..fc136ca045b 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java +++ b/Mage.Sets/src/mage/cards/s/SidequestPlayBlitzball.java @@ -2,18 +2,19 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.WatcherScope; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamagedEvent; @@ -32,25 +33,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SidequestPlayBlitzball extends CardImpl { +public final class SidequestPlayBlitzball extends TransformingDoubleFacedCard { public SidequestPlayBlitzball(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); - - this.secondSideCardClazz = mage.cards.w.WorldChampionCelestialWeapon.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{R}", + "World Champion, Celestial Weapon", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.EQUIPMENT}, "R" + ); + // Sidequest: Play Blitzball // At the beginning of combat on your turn, target creature you control gets +2/+0 until end of turn. Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(2, 0)); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the end of combat on your turn, if a player was dealt 6 or more combat damage this turn, transform this enchantment, then attach it to a creature you control. - this.addAbility(new TransformAbility()); ability = new EndOfCombatTriggeredAbility( new TransformSourceEffect(), TargetController.YOU, false ).withInterveningIf(SidequestPlayBlitzballCondition.instance).setTriggerPhrase("At the end of combat on your turn, "); ability.addEffect(new SidequestPlayBlitzballEffect()); - this.addAbility(ability, new SidequestPlayBlitzballWatcher()); + ability.addWatcher(new SidequestPlayBlitzballWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // World Champion, Celestial Weapon + // Double Overdrive -- Equipped creature gets +2/+0 and has double strike. + Ability eAbility = new SimpleStaticAbility(new BoostEquippedEffect(2, 0)); + eAbility.addEffect(new GainAbilityAttachedEffect( + DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has double strike")); + this.getRightHalfCard().addAbility(eAbility.withFlavorWord("Double Overdrive")); + + // Equip {3} + this.getRightHalfCard().addAbility(new EquipAbility(3)); } private SidequestPlayBlitzball(final SidequestPlayBlitzball card) { diff --git a/Mage.Sets/src/mage/cards/s/SidequestRaiseAChocobo.java b/Mage.Sets/src/mage/cards/s/SidequestRaiseAChocobo.java index da84b7ecc6d..ddca6715635 100644 --- a/Mage.Sets/src/mage/cards/s/SidequestRaiseAChocobo.java +++ b/Mage.Sets/src/mage/cards/s/SidequestRaiseAChocobo.java @@ -1,30 +1,38 @@ package mage.cards.s; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LandfallAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.ChocoboToken; +import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** * @author TheElk801 */ -public final class SidequestRaiseAChocobo extends CardImpl { +public final class SidequestRaiseAChocobo extends TransformingDoubleFacedCard { + private static final FilterPermanent filter = new FilterPermanent(SubType.BIRD, "Birds"); private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledPermanent(SubType.BIRD, "you control four or more Birds"), ComparisonType.MORE_THAN, 3 @@ -34,17 +42,32 @@ public final class SidequestRaiseAChocobo extends CardImpl { ); public SidequestRaiseAChocobo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); - - this.secondSideCardClazz = mage.cards.b.BlackChocobo.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{G}", + "Black Chocobo", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BIRD}, "G" + ); + // Sidequest: Raise a Chocobo // When this enchantment enters, create a 2/2 green Bird creature token with "Whenever a land you control enters, this token gets +1/+0 until end of turn." - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ChocoboToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ChocoboToken()))); // At the beginning of your first main phase, if you control four or more Birds, transform this enchantment. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfFirstMainTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(hint)); + + // Black Chocobo + this.getRightHalfCard().setPT(2, 2); + + // When this permanent transforms into Black Chocobo, search your library for a land card, put it onto the battlefield tapped, then shuffle. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_LAND_A), true) + )); + + // Landfall -- Whenever a land you control enters, Birds you control get +1/+0 until end of turn. + this.getRightHalfCard().addAbility(new LandfallAbility(new BoostControlledEffect( + 1, 0, Duration.EndOfTurn, filter, false + ))); } private SidequestRaiseAChocobo(final SidequestRaiseAChocobo card) { diff --git a/Mage.Sets/src/mage/cards/s/SightlessBrawler.java b/Mage.Sets/src/mage/cards/s/SightlessBrawler.java index c7edb114474..71d9f85cc8a 100644 --- a/Mage.Sets/src/mage/cards/s/SightlessBrawler.java +++ b/Mage.Sets/src/mage/cards/s/SightlessBrawler.java @@ -1,22 +1,22 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.CantAttackAloneAttachedEffect; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.BestowAbility; -import mage.abilities.keyword.CantAttackAloneAbility; 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.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** * @@ -35,7 +35,7 @@ public final class SightlessBrawler extends CardImpl { // Bestow 4W (If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.) this.addAbility(new BestowAbility(this, "{4}{W}")); // Sightless Brawler can't attack alone. - this.addAbility(new CantAttackAloneAbility()); + this.addAbility(new SimpleStaticAbility(new CantAttackAloneSourceEffect())); // Enchanted creature gets +3/+2 and can't attack alone. Effect effect = new BoostEnchantedEffect(3, 2, Duration.WhileOnBattlefield); effect.setText("Enchanted creature gets +3/+2"); diff --git a/Mage.Sets/src/mage/cards/s/SilverpeltWerewolf.java b/Mage.Sets/src/mage/cards/s/SilverpeltWerewolf.java deleted file mode 100644 index 8bf1157c998..00000000000 --- a/Mage.Sets/src/mage/cards/s/SilverpeltWerewolf.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author Loki - */ -public final class SilverpeltWerewolf extends CardImpl { - - public SilverpeltWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, null); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - this.power = new MageInt(4); - this.toughness = new MageInt(5); - - this.nightCard = true; - - // Whenever Silverpelt Werewolf deals combat damage to a player, draw a card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Silverpelt Werewolf. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private SilverpeltWerewolf(final SilverpeltWerewolf card) { - super(card); - } - - @Override - public SilverpeltWerewolf copy() { - return new SilverpeltWerewolf(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/Simulacrum.java b/Mage.Sets/src/mage/cards/s/Simulacrum.java index 282bbf88232..5f070c4a698 100644 --- a/Mage.Sets/src/mage/cards/s/Simulacrum.java +++ b/Mage.Sets/src/mage/cards/s/Simulacrum.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -14,6 +12,8 @@ import mage.game.Game; import mage.target.common.TargetControlledCreaturePermanent; import mage.watchers.common.AmountOfDamageAPlayerReceivedThisTurnWatcher; +import java.util.UUID; + /** * * @author MTGfan @@ -22,14 +22,13 @@ public final class Simulacrum extends CardImpl { public Simulacrum(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); - + // You gain life equal to the damage dealt to you this turn. Simulacrum deals damage to target creature you control equal to the damage dealt to you this turn. - this.getSpellAbility().addEffect(new GainLifeEffect(new SimulacrumAmount(), "You gain life equal to the damage dealt to you this turn.")); + this.getSpellAbility().addEffect(new GainLifeEffect(SimulacrumAmount.instance, "You gain life equal to the damage dealt to you this turn.")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - Effect effect = new DamageTargetEffect(new SimulacrumAmount(), true, "target creature you control", true); - effect.setText(" {this} deals damage to target creature you control equal to the damage dealt to you this turn."); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new DamageTargetEffect(SimulacrumAmount.instance) + .setText("{this} deals damage to target creature you control equal to the damage dealt to you this turn")); this.getSpellAbility().addWatcher(new AmountOfDamageAPlayerReceivedThisTurnWatcher()); } @@ -43,12 +42,13 @@ public final class Simulacrum extends CardImpl { } } -class SimulacrumAmount implements DynamicValue { +enum SimulacrumAmount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class); - if(watcher != null) { + if (watcher != null) { return watcher.getAmountOfDamageReceivedThisTurn(sourceAbility.getControllerId()); } return 0; @@ -56,7 +56,7 @@ class SimulacrumAmount implements DynamicValue { @Override public SimulacrumAmount copy() { - return new SimulacrumAmount(); + return this; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SinnersJudgment.java b/Mage.Sets/src/mage/cards/s/SinnersJudgment.java deleted file mode 100644 index 2014fb6d7d0..00000000000 --- a/Mage.Sets/src/mage/cards/s/SinnersJudgment.java +++ /dev/null @@ -1,90 +0,0 @@ -package mage.cards.s; - -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPlayer; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SinnersJudgment extends CardImpl { - - public SinnersJudgment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.subtype.add(SubType.CURSE); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant player - TargetPlayer auraTarget = new TargetPlayer(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // At the beginning of your upkeep, put a judgment counter on Sinner's Judgment. Then if there are three or more judgment counters on it, enchanted player loses the game. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance())); - ability.addEffect(new SinnersJudgmentEffect()); - this.addAbility(ability); - - // If Sinner's Judgment would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private SinnersJudgment(final SinnersJudgment card) { - super(card); - } - - @Override - public SinnersJudgment copy() { - return new SinnersJudgment(this); - } -} - -class SinnersJudgmentEffect extends OneShotEffect { - - SinnersJudgmentEffect() { - super(Outcome.Benefit); - staticText = "Then if there are three or more judgment counters on it, enchanted player loses the game"; - } - - private SinnersJudgmentEffect(final SinnersJudgmentEffect effect) { - super(effect); - } - - @Override - public SinnersJudgmentEffect copy() { - return new SinnersJudgmentEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return Optional - .ofNullable(source.getSourcePermanentOrLKI(game)) - .filter(permanent -> permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3) - .map(Permanent::getAttachedTo) - .map(game::getPlayer) - .filter(player -> { - player.lost(game); - return true; - }) - .isPresent(); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SinuousPredator.java b/Mage.Sets/src/mage/cards/s/SinuousPredator.java deleted file mode 100644 index d96130e866e..00000000000 --- a/Mage.Sets/src/mage/cards/s/SinuousPredator.java +++ /dev/null @@ -1,42 +0,0 @@ - -package mage.cards.s; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.combat.CantBeBlockedByMoreThanOneSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; - -/** - * - * @author fireshoes - */ -public final class SinuousPredator extends CardImpl { - - public SinuousPredator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Sinuous Predator can't be blocked by more than one creature. - this.addAbility(new SimpleStaticAbility(new CantBeBlockedByMoreThanOneSourceEffect())); - } - - private SinuousPredator(final SinuousPredator card) { - super(card); - } - - @Override - public SinuousPredator copy() { - return new SinuousPredator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SkewerSlinger.java b/Mage.Sets/src/mage/cards/s/SkewerSlinger.java index d529cd33c42..d391f503266 100644 --- a/Mage.Sets/src/mage/cards/s/SkewerSlinger.java +++ b/Mage.Sets/src/mage/cards/s/SkewerSlinger.java @@ -30,7 +30,7 @@ public final class SkewerSlinger extends CardImpl { // Whenever Skewer Slinger blocks or becomes blocked by a creature, Skewer Slinger deals 1 damage to that creature. this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility( - new DamageTargetEffect(1, true, "that creature") + new DamageTargetEffect(1).withTargetDescription("that creature") )); } diff --git a/Mage.Sets/src/mage/cards/s/SkinInvasion.java b/Mage.Sets/src/mage/cards/s/SkinInvasion.java index 38647f13455..dda91e54c88 100644 --- a/Mage.Sets/src/mage/cards/s/SkinInvasion.java +++ b/Mage.Sets/src/mage/cards/s/SkinInvasion.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,45 +9,46 @@ import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -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.cards.TransformingDoubleFacedCard; +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 LevelX2 */ -public final class SkinInvasion extends CardImpl { +public final class SkinInvasion extends TransformingDoubleFacedCard { public SkinInvasion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R}"); - this.subtype.add(SubType.AURA); - - this.secondSideCardClazz = mage.cards.s.SkinShedder.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "{R}", + "Skin Shedder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT, SubType.HORROR}, "R" + ); + // Skin Invasion // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + this.getLeftHalfCard().getSpellAbility().addTarget(auraTarget); + this.getLeftHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Enchanted creature attacks each combat if able. - this.addAbility(new SimpleStaticAbility( + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( new AttacksIfAbleAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA))); // When enchanted creature dies, return Skin Invasion to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesAttachedTriggeredAbility(new SkinInvasionEffect(), "enchanted creature", false)); + this.getLeftHalfCard().addAbility(new DiesAttachedTriggeredAbility(new SkinInvasionEffect(), "enchanted creature", false)); + + // Skin Shedder + this.getRightHalfCard().setPT(3, 4); } private SkinInvasion(final SkinInvasion card) { diff --git a/Mage.Sets/src/mage/cards/s/SkinShedder.java b/Mage.Sets/src/mage/cards/s/SkinShedder.java deleted file mode 100644 index 280214dbb26..00000000000 --- a/Mage.Sets/src/mage/cards/s/SkinShedder.java +++ /dev/null @@ -1,38 +0,0 @@ - -package mage.cards.s; - -import java.util.UUID; -import mage.MageInt; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author LevelX2 - */ -public final class SkinShedder extends CardImpl { - - public SkinShedder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.INSECT); - this.subtype.add(SubType.HORROR); - this.color.setRed(true); - - this.nightCard = true; - - this.power = new MageInt(3); - this.toughness = new MageInt(4); - } - - private SkinShedder(final SkinShedder card) { - super(card); - } - - @Override - public SkinShedder copy() { - return new SkinShedder(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/s/SkyclaveAerialist.java b/Mage.Sets/src/mage/cards/s/SkyclaveAerialist.java index 07486d3175c..d56ceaf0eb2 100644 --- a/Mage.Sets/src/mage/cards/s/SkyclaveAerialist.java +++ b/Mage.Sets/src/mage/cards/s/SkyclaveAerialist.java @@ -1,38 +1,54 @@ package mage.cards.s; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; 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 java.util.UUID; /** * @author TheElk801 */ -public final class SkyclaveAerialist extends CardImpl { +public final class SkyclaveAerialist extends TransformingDoubleFacedCard { public SkyclaveAerialist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MERFOLK, SubType.SCOUT}, "{1}{U}", + "Skyclave Invader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.MERFOLK, SubType.SCOUT}, "UG" + ); - this.subtype.add(SubType.MERFOLK); - this.subtype.add(SubType.SCOUT); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SkyclaveInvader.class; + // Skyclave Aerialist + this.getLeftHalfCard().setPT(2, 1); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // {4}{G/P}: Transform Skyclave Aerialist. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G/P}"))); + + // Skyclave Invader + this.getRightHalfCard().setPT(2, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When this creature transforms into Skyclave Invader, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new SkyclaveInvaderEffect())); } private SkyclaveAerialist(final SkyclaveAerialist card) { @@ -44,3 +60,38 @@ public final class SkyclaveAerialist extends CardImpl { return new SkyclaveAerialist(this); } } + +class SkyclaveInvaderEffect extends OneShotEffect { + + SkyclaveInvaderEffect() { + super(Outcome.Benefit); + staticText = "look at the top card of your library. If it's a land card, you may put it onto the battlefield. " + + "If you don't put the card onto the battlefield, put it into your hand"; + } + + private SkyclaveInvaderEffect(final SkyclaveInvaderEffect effect) { + super(effect); + } + + @Override + public SkyclaveInvaderEffect copy() { + return new SkyclaveInvaderEffect(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(source, null, new CardsImpl(card), game); + return player.moveCards(card, card.isLand(game) && player.chooseUse( + Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield or into your hand?", + null, "Battlefield", "Hand", source, game + ) ? Zone.BATTLEFIELD : Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkyclaveInvader.java b/Mage.Sets/src/mage/cards/s/SkyclaveInvader.java deleted file mode 100644 index dec33c9ee6e..00000000000 --- a/Mage.Sets/src/mage/cards/s/SkyclaveInvader.java +++ /dev/null @@ -1,88 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.FlyingAbility; -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.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SkyclaveInvader extends CardImpl { - - public SkyclaveInvader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.MERFOLK); - this.subtype.add(SubType.SCOUT); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.color.setBlue(true); - this.color.setGreen(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // When this creature transforms into Skyclave Invader, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand. - this.addAbility(new TransformIntoSourceTriggeredAbility(new SkyclaveInvaderEffect())); - } - - private SkyclaveInvader(final SkyclaveInvader card) { - super(card); - } - - @Override - public SkyclaveInvader copy() { - return new SkyclaveInvader(this); - } -} - -class SkyclaveInvaderEffect extends OneShotEffect { - - SkyclaveInvaderEffect() { - super(Outcome.Benefit); - staticText = "look at the top card of your library. If it's a land card, you may put it onto the battlefield. " + - "If you don't put the card onto the battlefield, put it into your hand"; - } - - private SkyclaveInvaderEffect(final SkyclaveInvaderEffect effect) { - super(effect); - } - - @Override - public SkyclaveInvaderEffect copy() { - return new SkyclaveInvaderEffect(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(source, null, new CardsImpl(card), game); - return player.moveCards(card, card.isLand(game) && player.chooseUse( - Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield or into your hand?", - null, "Battlefield", "Hand", source, game - ) ? Zone.BATTLEFIELD : Zone.HAND, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SlicerHighSpeedAntagonist.java b/Mage.Sets/src/mage/cards/s/SlicerHighSpeedAntagonist.java deleted file mode 100644 index 61fb781a073..00000000000 --- a/Mage.Sets/src/mage/cards/s/SlicerHighSpeedAntagonist.java +++ /dev/null @@ -1,59 +0,0 @@ -package mage.cards.s; - -import java.util.UUID; - -import mage.MageInt; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.abilities.keyword.LivingMetalAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -/** - * @author grimreap124 - */ -public final class SlicerHighSpeedAntagonist extends CardImpl { - - public SlicerHighSpeedAntagonist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.ARTIFACT }, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(3); - this.toughness = new MageInt(2); - this.color.setRed(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // First strike - this.addAbility(FirstStrikeAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Whenever Slicer deals combat damage to a player, convert it at end of combat. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new CreateDelayedTriggeredAbilityEffect( - new AtTheEndOfCombatDelayedTriggeredAbility(new TransformSourceEffect())) - .setText("convert it at end of combat"), - false)); - - } - - private SlicerHighSpeedAntagonist(final SlicerHighSpeedAntagonist card) { - super(card); - } - - @Override - public SlicerHighSpeedAntagonist copy() { - return new SlicerHighSpeedAntagonist(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SlicerHiredMuscle.java b/Mage.Sets/src/mage/cards/s/SlicerHiredMuscle.java index 8e5c77167ec..183989880be 100644 --- a/Mage.Sets/src/mage/cards/s/SlicerHiredMuscle.java +++ b/Mage.Sets/src/mage/cards/s/SlicerHiredMuscle.java @@ -1,56 +1,76 @@ package mage.cards.s; -import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.HasteAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.CantBeSacrificedSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.continuous.CantBeSacrificedSourceEffect; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; +import mage.abilities.keyword.*; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; -import mage.game.Game; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; import mage.players.Player; -import mage.abilities.common.SimpleStaticAbility; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** * @author grimreap124 */ -public final class SlicerHiredMuscle extends CardImpl { +public final class SlicerHiredMuscle extends TransformingDoubleFacedCard { public SlicerHiredMuscle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.ARTIFACT, CardType.CREATURE }, "{4}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{4}{R}", + "Slicer, High-Speed Antagonist", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "R" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.s.SlicerHighSpeedAntagonist.class; + // Slicer, Hired Muscle + this.getLeftHalfCard().setPT(3, 4); // More Than Meets the Eye {2}{R} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{R}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{R}")); // Double strike - this.addAbility(DoubleStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(DoubleStrikeAbility.getInstance()); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // At the beginning of each opponent's upkeep, you may have that player gain // control of Slicer until end of turn. If you do, untap Slicer, goad it, and it // can't be sacrificed this turn. If you don't, convert it. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new SlicerHiredMuscleUpkeepEffect(), + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.OPPONENT, new SlicerHiredMuscleUpkeepEffect(), false)); + // Slicer, High-Speed Antagonist + this.getRightHalfCard().setPT(3, 2); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // First strike + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Whenever Slicer deals combat damage to a player, convert it at end of combat. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new TransformSourceEffect())) + .setText("convert it at end of combat"), + false)); } private SlicerHiredMuscle(final SlicerHiredMuscle card) { @@ -104,8 +124,8 @@ class SlicerHiredMuscleUpkeepEffect extends OneShotEffect { // Goad game.addEffect(new GoadTargetEffect() - .setDuration(Duration.EndOfTurn) - .setTargetPointer(new FixedTarget(sourcePermanent, game)), + .setDuration(Duration.EndOfTurn) + .setTargetPointer(new FixedTarget(sourcePermanent, game)), source); // Can't be sacrificed diff --git a/Mage.Sets/src/mage/cards/s/SlimefootAndSquee.java b/Mage.Sets/src/mage/cards/s/SlimefootAndSquee.java index 4a8be95b0bc..4b8f9549464 100644 --- a/Mage.Sets/src/mage/cards/s/SlimefootAndSquee.java +++ b/Mage.Sets/src/mage/cards/s/SlimefootAndSquee.java @@ -58,7 +58,7 @@ public final class SlimefootAndSquee extends CardImpl { ability.addCost(new SacrificeTargetCost(filter)); ability.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect() .setText("and up to one other target creature card from your graveyard to the battlefield")); - ability.addTarget(new TargetCardInYourGraveyard(filter2)); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SmellerbeeRebelFighter.java b/Mage.Sets/src/mage/cards/s/SmellerbeeRebelFighter.java new file mode 100644 index 00000000000..8902fc9366c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SmellerbeeRebelFighter.java @@ -0,0 +1,69 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.DiscardHandCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.AttackingCreatureCount; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +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.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SmellerbeeRebelFighter extends CardImpl { + + private static final DynamicValue xValue = new AttackingCreatureCount(); + private static final Hint hint = new ValueHint("Attacking creatures", xValue); + + public SmellerbeeRebelFighter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Other creatures you control have haste. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES, true + ))); + + // Whenever Smellerbee attacks, you may discard your hand. If you do, draw cards equal to the number of attacking creatures. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(xValue) + .setText("draw cards equal to the number of attacking creatures"), + new DiscardHandCost() + )).addHint(hint)); + } + + private SmellerbeeRebelFighter(final SmellerbeeRebelFighter card) { + super(card); + } + + @Override + public SmellerbeeRebelFighter copy() { + return new SmellerbeeRebelFighter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SmolderingEgg.java b/Mage.Sets/src/mage/cards/s/SmolderingEgg.java index 7add8019e87..12cedaa41b5 100644 --- a/Mage.Sets/src/mage/cards/s/SmolderingEgg.java +++ b/Mage.Sets/src/mage/cards/s/SmolderingEgg.java @@ -1,6 +1,5 @@ package mage.cards.s; -import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.AbilityImpl; @@ -11,19 +10,21 @@ import mage.abilities.costs.mana.ManaCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; +import mage.target.common.TargetAnyTarget; import java.util.Optional; import java.util.UUID; @@ -31,24 +32,24 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SmolderingEgg extends CardImpl { +public final class SmolderingEgg extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.EMBER, 7); public SmolderingEgg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRAGON, SubType.EGG}, "{1}{R}", + "Ashmouth Dragon", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRAGON}, "R" + ); - this.subtype.add(SubType.DRAGON); - this.subtype.add(SubType.EGG); - this.power = new MageInt(0); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.a.AshmouthDragon.class; + // Smoldering Egg + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // Whenever you cast an instant or sorcery spell, put a number of ember counters on Smoldering Egg equal to the amount of mana spent to cast that spell. Then if Smoldering Egg has seven or more ember counters on it, remove them and transform Smoldering Egg. - this.addAbility(new TransformAbility()); Ability ability = new SpellCastControllerTriggeredAbility( new AddCountersSourceEffect(CounterType.EMBER.createInstance(), SmolderingEggValue.instance) .setText("put a number of ember counters on {this} equal to the amount of mana spent to cast that spell"), @@ -58,7 +59,20 @@ public final class SmolderingEgg extends CardImpl { new RemoveAllCountersSourceEffect(CounterType.EMBER), condition, "Then if {this} has seven or more ember counters on it, remove them and transform {this}" ).addEffect(new TransformSourceEffect())); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Ashmouth Dragon + this.getRightHalfCard().setPT(4, 4); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever you cast an instant or sorcery spell, Ashmouth Dragon deals 2 damage to any target. + Ability ability2 = new SpellCastControllerTriggeredAbility( + new DamageTargetEffect(2), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + ); + ability2.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(ability2); } private SmolderingEgg(final SmolderingEgg card) { diff --git a/Mage.Sets/src/mage/cards/s/SmolderingWerewolf.java b/Mage.Sets/src/mage/cards/s/SmolderingWerewolf.java index d20600ca9b2..d1c066b0a6a 100644 --- a/Mage.Sets/src/mage/cards/s/SmolderingWerewolf.java +++ b/Mage.Sets/src/mage/cards/s/SmolderingWerewolf.java @@ -1,17 +1,17 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -19,25 +19,33 @@ import java.util.UUID; /** * @author fireshoes */ -public final class SmolderingWerewolf extends CardImpl { +public final class SmolderingWerewolf extends TransformingDoubleFacedCard { public SmolderingWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{2}{R}{R}", + "Erupting Dreadwolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, "" + ); - this.secondSideCardClazz = mage.cards.e.EruptingDreadwolf.class; + // Smoldering Werewolf + this.getLeftHalfCard().setPT(3, 2); // When Smoldering Werewolf enters the battlefield, it deals 1 damage to each of up to two target creatures. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "it")); ability.addTarget(new TargetCreaturePermanent(0, 2)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {4}{R}{R}: Transform Smoldering Werewolf. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R}{R}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{R}{R}"))); + + // Erupting Dreadwolf + this.getRightHalfCard().setPT(6, 4); + + // Whenever Erupting Dreadwolf attacks, it deals 2 damage to any target. + Ability ability2 = new AttacksTriggeredAbility(new DamageTargetEffect(2, "it"), false); + ability2.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(ability2); } private SmolderingWerewolf(final SmolderingWerewolf card) { diff --git a/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java b/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java new file mode 100644 index 00000000000..bab01efc152 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkaAndSuki.java @@ -0,0 +1,85 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.AllyToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkaAndSuki extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Ally"); + + public SokkaAndSuki(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Sokka and Suki or another Ally you control enters, attach up to one target Equipment you control to that creature. + Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility( + new SokkaAndSukiEffect(), filter, false, true + ); + ability.addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + this.addAbility(ability); + + // Whenever an Equipment you control enters, create a 1/1 white Ally creature token. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + } + + private SokkaAndSuki(final SokkaAndSuki card) { + super(card); + } + + @Override + public SokkaAndSuki copy() { + return new SokkaAndSuki(this); + } +} + +class SokkaAndSukiEffect extends OneShotEffect { + + SokkaAndSukiEffect() { + super(Outcome.Benefit); + staticText = "attach up to one target Equipment you control to that creature"; + } + + private SokkaAndSukiEffect(final SokkaAndSukiEffect effect) { + super(effect); + } + + @Override + public SokkaAndSukiEffect copy() { + return new SokkaAndSukiEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = (Permanent) getValue("permanentEnteringBattlefield"); + Permanent equipment = game.getPermanent(getTargetPointer().getFirst(game, source)); + return creature != null && equipment != null && creature.addAttachment(equipment.getId(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java b/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java new file mode 100644 index 00000000000..ef87f0e83d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkaSwordmaster.java @@ -0,0 +1,97 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkaSwordmaster extends CardImpl { + + public SokkaSwordmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Equipment spells you cast cost {1} less to cast for each Ally you control. + this.addAbility(new SimpleStaticAbility(new SokkaSwordmasterEffect()).addHint(AffinityType.ALLIES.getHint())); + + // At the beginning of combat on your turn, attach up to one target Equipment you control to Sokka. + Ability ability = new BeginningOfCombatTriggeredAbility( + new AttachEffect(Outcome.BoostCreature, "attach up to one target Equipment you control to {this}" + )); + ability.addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_EQUIPMENT + )); + this.addAbility(ability); + } + + private SokkaSwordmaster(final SokkaSwordmaster card) { + super(card); + } + + @Override + public SokkaSwordmaster copy() { + return new SokkaSwordmaster(this); + } +} + +class SokkaSwordmasterEffect extends CostModificationEffectImpl { + + SokkaSwordmasterEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "Equipment spells you cast cost {1} less to cast for each Ally you control"; + } + + private SokkaSwordmasterEffect(final SokkaSwordmasterEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, game.getBattlefield().count(AffinityType.ALLIES.getFilter(), source.getControllerId(), source, game)); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return Optional + .ofNullable(abilityToModify) + .filter(SpellAbility.class::isInstance) + .filter(spellAbility -> spellAbility.isControlledBy(source.getControllerId())) + .map(SpellAbility.class::cast) + .map(spellAbility -> spellAbility.getCharacteristics(game)) + .filter(card -> card.hasSubtype(SubType.EQUIPMENT, game)) + .isPresent(); + } + + @Override + public SokkaSwordmasterEffect copy() { + return new SokkaSwordmasterEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SokkaTenaciousTactician.java b/Mage.Sets/src/mage/cards/s/SokkaTenaciousTactician.java new file mode 100644 index 00000000000..0c68b943bda --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkaTenaciousTactician.java @@ -0,0 +1,69 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.ProwessAbility; +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.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkaTenaciousTactician extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Allies"); + + public SokkaTenaciousTactician(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // Prowess + this.addAbility(new ProwessAbility()); + + // Other Allies you control have menace and prowess. + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(false), Duration.WhileOnBattlefield, filter, true + )); + ability.addEffect(new GainAbilityControlledEffect( + new ProwessAbility(), Duration.WhileOnBattlefield, filter, true + ).setText("and prowess")); + this.addAbility(ability); + + // Whenever you cast a noncreature spell, create a 1/1 white Ally creature token. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + } + + private SokkaTenaciousTactician(final SokkaTenaciousTactician card) { + super(card); + } + + @Override + public SokkaTenaciousTactician copy() { + return new SokkaTenaciousTactician(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SokkasCharge.java b/Mage.Sets/src/mage/cards/s/SokkasCharge.java new file mode 100644 index 00000000000..578d94dfb93 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkasCharge.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +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.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkasCharge extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ALLY); + + public SokkasCharge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // During your turn, Allies you control have double strike and lifelink. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAllEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter), + MyTurnCondition.instance, "during your turn, Allies you control have double strike" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilityAllEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, filter), + MyTurnCondition.instance, "and lifelink" + )); + this.addAbility(ability); + } + + private SokkasCharge(final SokkasCharge card) { + super(card); + } + + @Override + public SokkasCharge copy() { + return new SokkasCharge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SokkasSwordTraining.java b/Mage.Sets/src/mage/cards/s/SokkasSwordTraining.java new file mode 100644 index 00000000000..d88a1297cfa --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SokkasSwordTraining.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +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.SubType; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SokkasSwordTraining extends CardImpl { + + public SokkasSwordTraining(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + this.subtype.add(SubType.LESSON); + + // Target creature gets +2/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Create a Clue token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("
")); + } + + private SokkasSwordTraining(final SokkasSwordTraining card) { + super(card); + } + + @Override + public SokkasSwordTraining copy() { + return new SokkasSwordTraining(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoldOut.java b/Mage.Sets/src/mage/cards/s/SoldOut.java new file mode 100644 index 00000000000..eac68b43645 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoldOut.java @@ -0,0 +1,74 @@ +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.constants.Zone; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoldOut extends CardImpl { + + public SoldOut(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); + + // Exile target creature. If it was dealt damage this turn, create a Clue token. + this.getSpellAbility().addEffect(new SoldOutEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SoldOut(final SoldOut card) { + super(card); + } + + @Override + public SoldOut copy() { + return new SoldOut(this); + } +} + +class SoldOutEffect extends OneShotEffect { + + SoldOutEffect() { + super(Outcome.Benefit); + staticText = "exile target creature. If it was dealt damage this turn, create a Clue token"; + } + + private SoldOutEffect(final SoldOutEffect effect) { + super(effect); + } + + @Override + public SoldOutEffect copy() { + return new SoldOutEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + boolean flag = permanent.getDamage() > 0; + Optional.ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.moveCards(permanent, Zone.EXILED, source, game)); + if (flag) { + new ClueArtifactToken().putOntoBattlefield(1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SolidGround.java b/Mage.Sets/src/mage/cards/s/SolidGround.java new file mode 100644 index 00000000000..63c9d570457 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SolidGround.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.replacement.ModifyCountersAddedEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SolidGround extends CardImpl { + + public SolidGround(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // When this enchantment enters, earthbend 3. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(3)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // If one or more +1/+1 counters would be put on a permanent you control, that many plus one +1/+1 counters are put on it instead. + this.addAbility(new SimpleStaticAbility(new ModifyCountersAddedEffect( + StaticFilters.FILTER_CONTROLLED_PERMANENT, CounterType.P1P1 + ))); + } + + private SolidGround(final SolidGround card) { + super(card); + } + + @Override + public SolidGround copy() { + return new SolidGround(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SolitaryHunter.java b/Mage.Sets/src/mage/cards/s/SolitaryHunter.java index 29ca759d8e4..b79e69fc433 100644 --- a/Mage.Sets/src/mage/cards/s/SolitaryHunter.java +++ b/Mage.Sets/src/mage/cards/s/SolitaryHunter.java @@ -1,10 +1,9 @@ package mage.cards.s; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +12,26 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class SolitaryHunter extends CardImpl { +public final class SolitaryHunter extends TransformingDoubleFacedCard { public SolitaryHunter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{3}{G}", + "One of the Pack", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - - this.secondSideCardClazz = mage.cards.o.OneOfThePack.class; + // Solitary Hunter + this.getLeftHalfCard().setPT(3, 4); // At the beginning of each upkeep, if no spells were cast last turn, transform Solitary Hunter. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // One of the Pack + this.getRightHalfCard().setPT(5, 6); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform One of the Pack. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private SolitaryHunter(final SolitaryHunter card) { diff --git a/Mage.Sets/src/mage/cards/s/SolsticeRevelations.java b/Mage.Sets/src/mage/cards/s/SolsticeRevelations.java new file mode 100644 index 00000000000..250f545d70a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SolsticeRevelations.java @@ -0,0 +1,114 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SolsticeRevelations extends CardImpl { + + public SolsticeRevelations(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + this.subtype.add(SubType.LESSON); + + // Exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost if the spell's mana value is less than the number of Mountains you control. If you don't cast that card this way, put it into your hand. + this.getSpellAbility().addEffect(new SolsticeRevelationsEffect()); + + // Flashback {6}{R} + this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{6}{R}"))); + } + + private SolsticeRevelations(final SolsticeRevelations card) { + super(card); + } + + @Override + public SolsticeRevelations copy() { + return new SolsticeRevelations(this); + } +} + +enum SolsticeRevelationsPredicate implements ObjectSourcePlayerPredicate { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.MOUNTAIN); + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getManaValue() + < game.getBattlefield().count(filter, input.getPlayerId(), input.getSource(), game); + } +} + +class SolsticeRevelationsEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(SolsticeRevelationsPredicate.instance); + } + + SolsticeRevelationsEffect() { + super(Outcome.Benefit); + staticText = "exile cards from the top of your library until you exile a nonland card. " + + "You may cast that card without paying its mana cost if the spell's mana value is less than " + + "the number of Mountains you control. If you don't cast that card this way, put it into your hand"; + } + + private SolsticeRevelationsEffect(final SolsticeRevelationsEffect effect) { + super(effect); + } + + @Override + public SolsticeRevelationsEffect copy() { + return new SolsticeRevelationsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = getCard(player, game, source); + if (card == null) { + return false; + } + if (!CardUtil.castSpellWithAttributesForFree(player, source, game, card, filter)) { + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } + + private static Card getCard(Player player, Game game, Ability source) { + for (Card card : player.getLibrary().getCards(game)) { + player.moveCards(card, Zone.EXILED, source, game); + game.processAction(); + if (!card.isLand(game)) { + return card; + } + } + return null; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java b/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java index 7f8e196f6cd..ca31507c3e7 100644 --- a/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java +++ b/Mage.Sets/src/mage/cards/s/SomberwaldVigilante.java @@ -25,7 +25,7 @@ public final class SomberwaldVigilante extends CardImpl { this.toughness = new MageInt(1); // Whenever Somberwald Vigilante becomes blocked by a creature, Somberwald Vigilante deals 1 damage to that creature. - this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1, true, "that creature"), false)); + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature"), false)); } private SomberwaldVigilante(final SomberwaldVigilante card) { diff --git a/Mage.Sets/src/mage/cards/s/SorcerersBroom.java b/Mage.Sets/src/mage/cards/s/SorcerersBroom.java index e4511c9179c..d2a3e0c89b8 100644 --- a/Mage.Sets/src/mage/cards/s/SorcerersBroom.java +++ b/Mage.Sets/src/mage/cards/s/SorcerersBroom.java @@ -9,8 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import java.util.UUID; @@ -19,12 +18,6 @@ import java.util.UUID; */ public final class SorcerersBroom extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public SorcerersBroom(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); @@ -35,7 +28,7 @@ public final class SorcerersBroom extends CardImpl { // Whenever you sacrifice another permanent, you may pay {3}. If you do, create a token that's a copy of Sorcerer's Broom. this.addAbility(new SacrificePermanentTriggeredAbility( new DoIfCostPaid(new CreateTokenCopySourceEffect(), new GenericManaCost(3)), - filter + StaticFilters.FILTER_ANOTHER_PERMANENT )); } diff --git a/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java b/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java index ccbbb37b09e..13eeb95a616 100644 --- a/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java +++ b/Mage.Sets/src/mage/cards/s/SorinOfHouseMarkov.java @@ -1,18 +1,38 @@ package mage.cards.s; -import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.condition.common.YouGainedLifeCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTypeTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.keyword.ExtortAbility; import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FoodToken; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.PlayerGainedLifeWatcher; import java.util.UUID; @@ -20,33 +40,73 @@ import java.util.UUID; /** * @author Susucr */ -public final class SorinOfHouseMarkov extends CardImpl { +public final class SorinOfHouseMarkov extends TransformingDoubleFacedCard { private static final Condition condition = new YouGainedLifeCondition(ComparisonType.MORE_THAN, 2); private static final Hint hint = new ConditionHint(condition); + private static final FilterPermanent filterWhite = new FilterPermanent("white permanent other than that creature or {this}"); + private static final Condition conditionWhite = new PermanentsOnTheBattlefieldCondition(filterWhite, true); + private static final Hint hintWhite = new ConditionHint(conditionWhite, "you control another white permanent"); + + static { + filterWhite.add(new ColorPredicate(ObjectColor.WHITE)); + filterWhite.add(AnotherPredicate.instance); + filterWhite.add(SorinRavenousNeonatePredicate.instance); + } + public SorinOfHouseMarkov(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE}, "{1}{B}", + "Sorin, Ravenous Neonate", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.SORIN}, "WB" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.power = new MageInt(1); - this.toughness = new MageInt(4); + // Sorin of House Markov + this.getLeftHalfCard().setPT(1, 4); - this.secondSideCardClazz = SorinRavenousNeonate.class; - - // Flying - this.addAbility(LifelinkAbility.getInstance()); + // Lifelink + this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance()); // Extort - this.addAbility(new ExtortAbility()); + this.getLeftHalfCard().addAbility(new ExtortAbility()); // At the beginning of your postcombat main phase, if you gained 3 or more life this turn, exile Sorin of House Markov, then return him to the battlefield transformed under his owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfPostcombatMainTriggeredAbility( + Ability ability = new BeginningOfPostcombatMainTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), false - ).withInterveningIf(condition).addHint(hint), new PlayerGainedLifeWatcher()); + ).withInterveningIf(condition).addHint(hint); + ability.addWatcher(new PlayerGainedLifeWatcher()); + this.getLeftHalfCard().addAbility(ability); + + // Sorin, Ravenous Neonate + this.getRightHalfCard().setStartingLoyalty(3); + + // Extort + this.getRightHalfCard().addAbility(new ExtortAbility()); + + // +2: Create a Food token. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new FoodToken()), 2)); + + // -1: Sorin, Ravenous Neonate deals damage equal to the amount of life you gained this turn to any target. + ability = new LoyaltyAbility( + new DamageTargetEffect(ControllerGainedLifeCount.instance) + .setText("{this} deals damage equal to the amount of life you gained this turn to any target"), + -1 + ); + ability.addTarget(new TargetAnyTarget()); + ability.addWatcher(new PlayerGainedLifeWatcher()); + this.getRightHalfCard().addAbility(ability.addHint(ControllerGainedLifeCount.getHint())); + + // -6: Gain control of target creature. It becomes a Vampire in addition to its other types. Put a lifelink counter on it if you control a white permanent other than that creature or Sorin. + Ability ability2 = new LoyaltyAbility(new GainControlTargetEffect(Duration.EndOfGame), -6); + ability2.addTarget(new TargetCreaturePermanent()); + ability2.addEffect(new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.VAMPIRE, false) + .setText("It becomes a Vampire in addition to its other types")); + ability2.addEffect(new ConditionalOneShotEffect( + new AddCountersTargetEffect(CounterType.LIFELINK.createInstance()), + conditionWhite, "Put a lifelink counter on it if you control a white permanent other than that creature or {this}" + )); + this.getRightHalfCard().addAbility(ability2.addHint(hintWhite)); } private SorinOfHouseMarkov(final SorinOfHouseMarkov card) { @@ -58,3 +118,16 @@ public final class SorinOfHouseMarkov extends CardImpl { return new SorinOfHouseMarkov(this); } } + +enum SorinRavenousNeonatePredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Ability source = input.getSource(); + Permanent permanent = input.getObject(); + return source != null + && permanent != null + && !permanent.getId().equals(source.getFirstTarget()); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SorinRavenousNeonate.java b/Mage.Sets/src/mage/cards/s/SorinRavenousNeonate.java deleted file mode 100644 index e294dad377c..00000000000 --- a/Mage.Sets/src/mage/cards/s/SorinRavenousNeonate.java +++ /dev/null @@ -1,113 +0,0 @@ -package mage.cards.s; - -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.continuous.BecomesCreatureTypeTargetEffect; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -import mage.abilities.keyword.ExtortAbility; -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.FilterPermanent; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.FoodToken; -import mage.target.common.TargetAnyTarget; -import mage.target.common.TargetCreaturePermanent; -import mage.watchers.common.PlayerGainedLifeWatcher; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class SorinRavenousNeonate extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("white permanent other than that creature or {this}"); - private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true); - private static final Hint hint = new ConditionHint(condition, "you control another white permanent"); - - static { - filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(AnotherPredicate.instance); - filter.add(SorinRavenousNeonatePredicate.instance); - } - - public SorinRavenousNeonate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SORIN); - this.setStartingLoyalty(3); - - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Extort - this.addAbility(new ExtortAbility()); - - // +2: Create a Food token. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new FoodToken()), 2)); - - // -1: Sorin, Ravenous Neonate deals damage equal to the amount of life you gained this turn to any target. - Ability ability = new LoyaltyAbility( - new DamageTargetEffect(ControllerGainedLifeCount.instance) - .setText("{this} deals damage equal to the amount of life you gained this turn to any target"), - -1 - ); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability.addHint(ControllerGainedLifeCount.getHint()), new PlayerGainedLifeWatcher()); - - // -6: Gain control of target creature. It becomes a Vampire in addition to its other types. Put a lifelink counter on it if you control a white permanent other than that creature or Sorin. - ability = new LoyaltyAbility(new GainControlTargetEffect(Duration.EndOfGame), -6); - ability.addTarget(new TargetCreaturePermanent()); - ability.addEffect(new BecomesCreatureTypeTargetEffect(Duration.EndOfGame, SubType.VAMPIRE, false) - .setText("It becomes a Vampire in addition to its other types")); - ability.addEffect(new ConditionalOneShotEffect( - new AddCountersTargetEffect(CounterType.LIFELINK.createInstance()), - condition, "Put a lifelink counter on it if you control a white permanent other than that creature or {this}" - )); - this.addAbility(ability.addHint(hint)); - } - - private SorinRavenousNeonate(final SorinRavenousNeonate card) { - super(card); - } - - @Override - public SorinRavenousNeonate copy() { - return new SorinRavenousNeonate(this); - } -} - -enum SorinRavenousNeonatePredicate implements ObjectSourcePlayerPredicate { - instance; - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - Ability source = input.getSource(); - Permanent permanent = input.getObject(); - return source != null - && permanent != null - && !permanent.getId().equals(source.getFirstTarget()); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java b/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java index f18b7cf1613..5b4fe81e8b6 100644 --- a/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java +++ b/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.MageInt; @@ -93,7 +92,7 @@ class SoulOfShandalarEffect extends OneShotEffect { class SoulOfShandalarTarget extends TargetPermanent { - public SoulOfShandalarTarget() { + SoulOfShandalarTarget() { super(0, 1, new FilterCreaturePermanent("creature that the targeted player or planeswalker's controller controls")); } diff --git a/Mage.Sets/src/mage/cards/s/SoulSeizer.java b/Mage.Sets/src/mage/cards/s/SoulSeizer.java index aa0cebb6f39..981e5101fd8 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSeizer.java +++ b/Mage.Sets/src/mage/cards/s/SoulSeizer.java @@ -1,21 +1,24 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.ControlEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.target.Target; import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster; import java.util.UUID; @@ -23,26 +26,36 @@ import java.util.UUID; /** * @author BetaSteward */ -public final class SoulSeizer extends CardImpl { +public final class SoulSeizer extends TransformingDoubleFacedCard { public SoulSeizer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); - this.subtype.add(SubType.SPIRIT); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{3}{U}{U}", + "Ghastly Haunting", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "U" + ); - this.secondSideCardClazz = mage.cards.g.GhastlyHaunting.class; + // Soul Seizer + this.getLeftHalfCard().setPT(1, 3); - this.power = new MageInt(1); - this.toughness = new MageInt(3); - - this.addAbility(FlyingAbility.getInstance()); + // Flying + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // When Soul Seizer deals combat damage to a player, you may transform it. If you do, attach it to target creature that player controls. - this.addAbility(new TransformAbility()); TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new SoulSeizerEffect(), true, true); ability.setTriggerPhrase("When {this} deals combat damage to a player, "); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE)); ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Ghastly Haunting + // Enchant creature + Target auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // You control enchanted creature. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ControlEnchantedEffect())); } private SoulSeizer(final SoulSeizer card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java index 538dcae5506..85b8aadc9c5 100644 --- a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java +++ b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java @@ -1,6 +1,7 @@ package mage.cards.s; import mage.abilities.Ability; +import mage.abilities.common.CanBlockOnlyFlyingAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -9,17 +10,15 @@ 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.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.PutCards; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -28,16 +27,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SoulcipherBoard extends CardImpl { +public final class SoulcipherBoard extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.OMEN, ComparisonType.EQUAL_TO, 0); public SoulcipherBoard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); - this.secondSideCardClazz = mage.cards.c.CipherboundSpirit.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{U}", + "Cipherbound Spirit", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U" + ); + // Soulcipher Board // Soulcipher Board enters the battlefield with three omen counters on it. - this.addAbility(new EntersBattlefieldAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.OMEN.createInstance(3)), "with three omen counters on it" )); @@ -47,19 +50,32 @@ public final class SoulcipherBoard extends CardImpl { new LookLibraryAndPickControllerEffect(2, 1, PutCards.GRAVEYARD, PutCards.TOP_ANY), new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Whenever a creature card is put into your graveyard from anywhere, remove an omen counter from Soulcipher Board. Then if it has no omen counters on it, transform it. - this.addAbility(new TransformAbility()); - ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + Ability ability2 = new PutCardIntoGraveFromAnywhereAllTriggeredAbility( new RemoveCounterSourceEffect(CounterType.OMEN.createInstance()), false, StaticFilters.FILTER_CARD_CREATURE_A, TargetController.YOU ); - ability.addEffect(new ConditionalOneShotEffect( + ability2.addEffect(new ConditionalOneShotEffect( new TransformSourceEffect(), condition, "Then if it has no omen counters on it, transform it" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability2); + + // Cipherbound Spirit + this.getRightHalfCard().setPT(3, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Cipherbound Spirit can block only creatures with flying. + this.getRightHalfCard().addAbility(new CanBlockOnlyFlyingAbility()); + + // {3}{U}: Draw two cards, then discard a card. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility( + new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl<>("{3}{U}") + )); } private SoulcipherBoard(final SoulcipherBoard card) { diff --git a/Mage.Sets/src/mage/cards/s/SouthPoleVoyager.java b/Mage.Sets/src/mage/cards/s/SouthPoleVoyager.java new file mode 100644 index 00000000000..4101ea86db8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SouthPoleVoyager.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; +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 SouthPoleVoyager extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Ally"); + + public SouthPoleVoyager(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SCOUT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever this creature or another Ally you control enters, you gain 1 life. If this is the second time this ability has resolved this turn, draw a card. + Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility(new GainLifeEffect(1), filter, false, true); + ability.addEffect(new IfAbilityHasResolvedXTimesEffect(2, new DrawCardSourceControllerEffect(1))); + this.addAbility(ability); + } + + private SouthPoleVoyager(final SouthPoleVoyager card) { + super(card); + } + + @Override + public SouthPoleVoyager copy() { + return new SouthPoleVoyager(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SouthernAirTemple.java b/Mage.Sets/src/mage/cards/s/SouthernAirTemple.java index ce184fcb615..b73e9dd010f 100644 --- a/Mage.Sets/src/mage/cards/s/SouthernAirTemple.java +++ b/Mage.Sets/src/mage/cards/s/SouthernAirTemple.java @@ -2,21 +2,15 @@ package mage.cards.s; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; import mage.abilities.effects.common.counter.AddCountersAllEffect; -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.SuperType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; import java.util.UUID; @@ -25,14 +19,6 @@ import java.util.UUID; */ public final class SouthernAirTemple extends CardImpl { - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.SHRINE)); - private static final Hint hint = new ValueHint("Shrines you control", xValue); - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SHRINE, "another Shrine you control"); - - static { - filter.add(AnotherPredicate.instance); - } - public SouthernAirTemple(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); @@ -41,13 +27,13 @@ public final class SouthernAirTemple extends CardImpl { // When Southern Air Temple enters, put X +1/+1 counters on each creature you control, where X is the number of Shrines you control. this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect( - CounterType.P1P1.createInstance(), xValue, StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("put X +1/+1 counters on each creature you control, where X is the number of Shrines you control")).addHint(hint)); + CounterType.P1P1.createInstance(), ShrinesYouControlCount.WHERE_X, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("put X +1/+1 counters on each creature you control, where X is the number of Shrines you control")).addHint(ShrinesYouControlCount.getHint())); // Whenever another Shrine you control enters, put a +1/+1 counter on each creature you control. this.addAbility(new EntersBattlefieldAllTriggeredAbility(new AddCountersAllEffect( CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE - ), filter)); + ), StaticFilters.FILTER_ANOTHER_CONTROLLED_SHRINE)); } private SouthernAirTemple(final SouthernAirTemple card) { diff --git a/Mage.Sets/src/mage/cards/s/SovereignsMacuahuitl.java b/Mage.Sets/src/mage/cards/s/SovereignsMacuahuitl.java deleted file mode 100644 index 86401a5368f..00000000000 --- a/Mage.Sets/src/mage/cards/s/SovereignsMacuahuitl.java +++ /dev/null @@ -1,44 +0,0 @@ -package mage.cards.s; - -import mage.abilities.common.EntersBattlefieldAttachToTarget; -import mage.abilities.common.SimpleStaticAbility; -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.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SovereignsMacuahuitl extends CardImpl { - - public SovereignsMacuahuitl(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.subtype.add(SubType.EQUIPMENT); - this.nightCard = true; - this.color.setRed(true); - - // When Sovereign's Macuahuitl enters the battlefield, attach it to target creature you control. - this.addAbility(new EntersBattlefieldAttachToTarget()); - - // Equipped creature gets +2/+0. - this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0))); - - // Equip {2} - this.addAbility(new EquipAbility(2)); - } - - private SovereignsMacuahuitl(final SovereignsMacuahuitl card) { - super(card); - } - - @Override - public SovereignsMacuahuitl copy() { - return new SovereignsMacuahuitl(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SozinsComet.java b/Mage.Sets/src/mage/cards/s/SozinsComet.java new file mode 100644 index 00000000000..c318072ab96 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SozinsComet.java @@ -0,0 +1,39 @@ +package mage.cards.s; + +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.ForetellAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SozinsComet extends CardImpl { + + public SozinsComet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + + // Each creature you control gains firebending 5 until end of turn. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + new FirebendingAbility(5), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("each creature you control gains firebending 5 until end of turn")); + + // Foretell {2}{R} + this.addAbility(new ForetellAbility(this, "{2}{R}")); + } + + private SozinsComet(final SozinsComet card) { + super(card); + } + + @Override + public SozinsComet copy() { + return new SozinsComet(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Sparksmith.java b/Mage.Sets/src/mage/cards/s/Sparksmith.java index 7a11696bfc3..158c416bd05 100644 --- a/Mage.Sets/src/mage/cards/s/Sparksmith.java +++ b/Mage.Sets/src/mage/cards/s/Sparksmith.java @@ -1,35 +1,30 @@ - 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.TapSourceCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.common.DamageControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetAndYouEffect; 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.game.Game; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * * @author Plopman */ public final class Sparksmith extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Goblins on the battlefield"); - static { - filter.add(SubType.GOBLIN.getPredicate()); - } - private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); - public Sparksmith(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); this.subtype.add(SubType.GOBLIN); @@ -38,11 +33,8 @@ public final class Sparksmith extends CardImpl { this.toughness = new MageInt(1); // {tap}: Sparksmith deals X damage to target creature and X damage to you, where X is the number of Goblins on the battlefield. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(xValue) - .setText("{this} deals X damage to target creature"), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new SparksmithEffect(), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); - ability.addEffect(new DamageControllerEffect(xValue) - .setText("and X damage to you, where X is the number of Goblins on the battlefield")); this.addAbility(ability); } @@ -55,3 +47,35 @@ public final class Sparksmith extends CardImpl { return new Sparksmith(this); } } + +// too lazy to handle dynamic value properly in the common class +class SparksmithEffect extends OneShotEffect { + + + private static final FilterPermanent filter = new FilterPermanent("Goblins on the battlefield"); + static { + filter.add(SubType.GOBLIN.getPredicate()); + } + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + SparksmithEffect() { + super(Outcome.Benefit); + staticText = "{this} deals X damage to target creature and X damage to you, " + + "where X is the number of Goblins on the battlefield"; + } + + private SparksmithEffect(final SparksmithEffect effect) { + super(effect); + } + + @Override + public SparksmithEffect copy() { + return new SparksmithEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int amount = xValue.calculate(game, source, this); + return new DamageTargetAndYouEffect(amount, amount).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SparringDummy.java b/Mage.Sets/src/mage/cards/s/SparringDummy.java new file mode 100644 index 00000000000..f1aea71cad2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparringDummy.java @@ -0,0 +1,92 @@ +package mage.cards.s; + +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.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +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.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetImpl; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SparringDummy extends CardImpl { + + public SparringDummy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.SCARECROW); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {T}: Mill a card. You may put a land card milled this way into your hand. You gain 2 life if a Lesson card is milled this way. + this.addAbility(new SimpleActivatedAbility(new SparringDummyEffect(), new TapSourceCost())); + } + + private SparringDummy(final SparringDummy card) { + super(card); + } + + @Override + public SparringDummy copy() { + return new SparringDummy(this); + } +} + +class SparringDummyEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(SubType.LESSON); + + SparringDummyEffect() { + super(Outcome.Benefit); + staticText = "mill a card. You may put a land card milled this way into your hand. " + + "You gain 2 life if a Lesson card is milled this way"; + } + + private SparringDummyEffect(final SparringDummyEffect effect) { + super(effect); + } + + @Override + public SparringDummyEffect copy() { + return new SparringDummyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = player.millCards(1, source, game); + TargetCard target = new TargetCard(0, 1, Zone.ALL, StaticFilters.FILTER_CARD_LAND); + player.choose(Outcome.DrawCard, cards, target, source, game); + Optional.ofNullable(target) + .map(TargetImpl::getFirstTarget) + .map(game::getCard) + .ifPresent(card -> player.moveCards(card, Zone.HAND, source, game)); + if (cards.count(filter, game) > 0) { + player.gainLife(2, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpellruneHowler.java b/Mage.Sets/src/mage/cards/s/SpellruneHowler.java deleted file mode 100644 index e8c5b16fdcf..00000000000 --- a/Mage.Sets/src/mage/cards/s/SpellruneHowler.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.NightboundAbility; -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 SpellruneHowler extends CardImpl { - - public SpellruneHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // Whenever you cast an instant or sorcery spell, Spellrune Howler gets +2/+2 until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility( - new BoostSourceEffect(2, 2, Duration.EndOfTurn), - StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private SpellruneHowler(final SpellruneHowler card) { - super(card); - } - - @Override - public SpellruneHowler copy() { - return new SpellruneHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SpellrunePainter.java b/Mage.Sets/src/mage/cards/s/SpellrunePainter.java index db0d71157e1..b07d114ea56 100644 --- a/Mage.Sets/src/mage/cards/s/SpellrunePainter.java +++ b/Mage.Sets/src/mage/cards/s/SpellrunePainter.java @@ -1,11 +1,11 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -16,26 +16,38 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SpellrunePainter extends CardImpl { +public final class SpellrunePainter extends TransformingDoubleFacedCard { public SpellrunePainter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{2}{R}", + "Spellrune Howler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.s.SpellruneHowler.class; + // Spellrune Painter + this.getLeftHalfCard().setPT(2, 3); // Whenever you cast an instant or sorcery spell, Spellrune Painter gets +1/+1 until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Spellrune Howler + this.getRightHalfCard().setPT(3, 4); + + // Whenever you cast an instant or sorcery spell, Spellrune Howler gets +2/+2 until end of turn. + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private SpellrunePainter(final SpellrunePainter card) { diff --git a/Mage.Sets/src/mage/cards/s/Spellshock.java b/Mage.Sets/src/mage/cards/s/Spellshock.java index b7caa19b968..fe9e870337c 100644 --- a/Mage.Sets/src/mage/cards/s/Spellshock.java +++ b/Mage.Sets/src/mage/cards/s/Spellshock.java @@ -42,7 +42,7 @@ class SpellshockTriggeredAbility extends TriggeredAbilityImpl { public SpellshockTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player")); + super(Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("that player")); } @@ -76,4 +76,4 @@ class SpellshockTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a player casts a spell, {this} deals 2 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SpiderPunk.java b/Mage.Sets/src/mage/cards/s/SpiderPunk.java index 5c9245b121d..034d7423238 100644 --- a/Mage.Sets/src/mage/cards/s/SpiderPunk.java +++ b/Mage.Sets/src/mage/cards/s/SpiderPunk.java @@ -15,6 +15,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; @@ -34,7 +35,7 @@ import java.util.UUID; */ public final class SpiderPunk extends CardImpl { - static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SPIDER, "Spiders you control"); + static final FilterPermanent filter = new FilterPermanent(SubType.SPIDER, "Spiders you control"); public SpiderPunk(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -125,7 +126,7 @@ class SpiderPunkRiotETBEffect extends ReplacementEffectImpl { return creature != null && creature.getId() != source.getSourceId() && creature.isControlledBy(source.getControllerId()) - && creature.isCreature(game) + && SpiderPunk.filter.match(creature, source.getControllerId(), source, game) && !(creature instanceof PermanentToken); } @@ -154,4 +155,4 @@ class SpiderPunkRiotETBEffect extends ReplacementEffectImpl { public SpiderPunkRiotETBEffect copy() { return new SpiderPunkRiotETBEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SpiderSense.java b/Mage.Sets/src/mage/cards/s/SpiderSense.java index 1b75f437dcc..e7f8087dc5d 100644 --- a/Mage.Sets/src/mage/cards/s/SpiderSense.java +++ b/Mage.Sets/src/mage/cards/s/SpiderSense.java @@ -30,12 +30,12 @@ public final class SpiderSense extends CardImpl { public SpiderSense(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); - // Web-slinging {U} - this.addAbility(new WebSlingingAbility(this, "{U}")); - // Counter target instant spell, sorcery spell, or triggered ability. this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetStackObject(filter)); + + // Web-slinging {U} + this.addAbility(new WebSlingingAbility(this, "{U}")); } private SpiderSense(final SpiderSense card) { diff --git a/Mage.Sets/src/mage/cards/s/SpikedCorridorTorturePit.java b/Mage.Sets/src/mage/cards/s/SpikedCorridorTorturePit.java new file mode 100644 index 00000000000..74f6e2e05ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpikedCorridorTorturePit.java @@ -0,0 +1,83 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.DamagePlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.token.DevilToken; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpikedCorridorTorturePit extends RoomCard { + + public SpikedCorridorTorturePit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{3}{R}", "{3}{R}"); + + // Spiked Corridor + // When you unlock this door, create three 1/1 red Devil creature tokens with "When this token dies, it deals 1 damage to any target." + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility( + new CreateTokenEffect(new DevilToken(), 3), false, true + )); + + // Torture Pit + // If a source you control would deal noncombat damage to an opponent, it deals that much damage plus 2 instead. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new TorturePitEffect())); + } + + private SpikedCorridorTorturePit(final SpikedCorridorTorturePit card) { + super(card); + } + + @Override + public SpikedCorridorTorturePit copy() { + return new SpikedCorridorTorturePit(this); + } +} + +class TorturePitEffect extends ReplacementEffectImpl { + + TorturePitEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "if a source you control would deal noncombat damage to an opponent, " + + "it deals that much damage plus 2 instead"; + } + + private TorturePitEffect(final TorturePitEffect effect) { + super(effect); + } + + @Override + public TorturePitEffect copy() { + return new TorturePitEffect(this); + } + + @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 !((DamagePlayerEvent) event).isCombatDamage() + && source.isControlledBy(game.getControllerId(event.getSourceId())) + && game.getOpponents(source.getControllerId()).contains(event.getTargetId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.overflowInc(event.getAmount(), 2)); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java b/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java index 16d39d3d93d..593d0181194 100644 --- a/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java +++ b/Mage.Sets/src/mage/cards/s/SpikedPitTrap.java @@ -39,14 +39,11 @@ public final class SpikedPitTrap extends CardImpl { this.addAbility(ability); // 1-9 | Spiked Pit Trap deals 5 damage to that creature. - effect.addTableEntry(1, 9, new DamageTargetEffect( - 5, true, "that creature" - )); + effect.addTableEntry(1, 9, new DamageTargetEffect(5).withTargetDescription("that creature")); // 10-20 | Spike Pit Trap deals 5 damage to that creature. Create a Treasure token. - effect.addTableEntry(10, 20, new DamageTargetEffect( - 5, true, "that creature." - ), new CreateTokenEffect(new TreasureToken())); + effect.addTableEntry(10, 20, new DamageTargetEffect(5).withTargetDescription("that creature"), + new CreateTokenEffect(new TreasureToken())); } private SpikedPitTrap(final SpikedPitTrap card) { diff --git a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java b/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java deleted file mode 100644 index 49d9508989b..00000000000 --- a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java +++ /dev/null @@ -1,56 +0,0 @@ -package mage.cards.s; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.RemoveFromCombatTargetEffect; -import mage.abilities.effects.common.UntapTargetEffect; -import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterOpponentsCreaturePermanent; -import mage.filter.predicate.permanent.AttackingPredicate; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SpiresOfOrazca extends CardImpl { - - private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("attacking creature an opponent controls"); - - static { - filter.add(AttackingPredicate.instance); - } - - public SpiresOfOrazca(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); - - // {T}: Untap target attacking creature an opponent controls and remove it from combat. - Ability ability = new SimpleActivatedAbility( - new UntapTargetEffect() - .setText("Untap target attacking creature an opponent controls"), - new TapSourceCost() - ); - ability.addEffect(new RemoveFromCombatTargetEffect().setText("and remove it from combat")); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - } - - private SpiresOfOrazca(final SpiresOfOrazca card) { - super(card); - } - - @Override - public SpiresOfOrazca copy() { - return new SpiresOfOrazca(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java b/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java new file mode 100644 index 00000000000..9bb9f2375c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritWaterRevival.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.abilities.condition.common.WaterbendedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.ShuffleYourGraveyardIntoLibraryEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.keyword.WaterbendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpiritWaterRevival extends CardImpl { + + public SpiritWaterRevival(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}"); + + // As an additional cost to cast this spell, you may waterbend {6}. + this.addAbility(new WaterbendAbility(6)); + + // Draw two cards. If this spell's additional cost was paid, instead shuffle your graveyard into your library, draw seven cards, and you have no maximum hand size for the rest of the game. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new ShuffleYourGraveyardIntoLibraryEffect(), new DrawCardSourceControllerEffect(2), + WaterbendedCondition.instance, "draw two cards. If this spell's additional cost was paid, " + + "instead shuffle your graveyard into your library, draw seven cards, " + + "and you have no maximum hand size for the rest of the game" + ).addEffect(new DrawCardSourceControllerEffect(7)) + .addEffect(new AddContinuousEffectToGame(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.EndOfGame, MaximumHandSizeControllerEffect.HandSizeModification.SET + )))); + + // Exile Spirit Water Revival. + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); + } + + private SpiritWaterRevival(final SpiritWaterRevival card) { + super(card); + } + + @Override + public SpiritWaterRevival copy() { + return new SpiritWaterRevival(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Spiritualize.java b/Mage.Sets/src/mage/cards/s/Spiritualize.java index 143b0e2ac33..01b32b45836 100644 --- a/Mage.Sets/src/mage/cards/s/Spiritualize.java +++ b/Mage.Sets/src/mage/cards/s/Spiritualize.java @@ -62,8 +62,7 @@ class SpiritualizeTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.DAMAGED_PERMANENT; + return event.getType() == GameEvent.EventType.DAMAGED_BATCH_BY_SOURCE; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpitfireBastion.java b/Mage.Sets/src/mage/cards/s/SpitfireBastion.java deleted file mode 100644 index 89482efbd3e..00000000000 --- a/Mage.Sets/src/mage/cards/s/SpitfireBastion.java +++ /dev/null @@ -1,48 +0,0 @@ - -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.DamageTargetEffect; -import mage.abilities.mana.RedManaAbility; -import mage.constants.SuperType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; -import mage.target.common.TargetAnyTarget; - -/** - * - * @author TheElk801 - */ -public final class SpitfireBastion extends CardImpl { - - public SpitfireBastion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // {2}{R}, {T}: Spitfire Bastion deals 3 damage to any target. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3), new TapSourceCost()); - ability.addCost(new ManaCostsImpl<>("{2}{R}")); - ability.addTarget(new TargetAnyTarget()); - this.addAbility(ability); - } - - private SpitfireBastion(final SpitfireBastion card) { - super(card); - } - - @Override - public SpitfireBastion copy() { - return new SpitfireBastion(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SplinterTheMentor.java b/Mage.Sets/src/mage/cards/s/SplinterTheMentor.java new file mode 100644 index 00000000000..a978c9749b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SplinterTheMentor.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PartnerVariantType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.FilterPermanentThisOrAnother; +import mage.filter.StaticFilters; +import mage.game.permanent.token.MutagenToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SplinterTheMentor extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanentThisOrAnother( + StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN, false + ); + + public SplinterTheMentor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.RAT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever Splinter or another nontoken creature you control leaves the battlefield, create a Mutagen token. + this.addAbility(new LeavesBattlefieldAllTriggeredAbility(new CreateTokenEffect(new MutagenToken()), filter)); + + // Partner--Character select + this.addAbility(PartnerVariantType.CHARACTER_SELECT.makeAbility()); + } + + private SplinterTheMentor(final SplinterTheMentor card) { + super(card); + } + + @Override + public SplinterTheMentor copy() { + return new SplinterTheMentor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java b/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java index d9c7374a10f..19c939bd874 100644 --- a/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java +++ b/Mage.Sets/src/mage/cards/s/SpringLoadedSawblades.java @@ -2,45 +2,73 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.abilities.keyword.CraftAbility; +import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.FlashAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class SpringLoadedSawblades extends CardImpl { +public final class SpringLoadedSawblades extends TransformingDoubleFacedCard { + private static final FilterControlledPermanent bladeWheelFilter + = new FilterControlledArtifactPermanent("other untapped artifacts you control"); private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); static { filter.add(TappedPredicate.TAPPED); + bladeWheelFilter.add(AnotherPredicate.instance); + bladeWheelFilter.add(TappedPredicate.UNTAPPED); } public SpringLoadedSawblades(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); - this.secondSideCardClazz = mage.cards.b.BladewheelChariot.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{W}", + "Bladewheel Chariot", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "W"); + + this.getRightHalfCard().setPT(5, 5); // Flash - this.addAbility(FlashAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlashAbility.getInstance()); // When Spring-Loaded Sawblades enters the battlefield, it deals 5 damage to target tapped creature an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5, "it")); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with artifact {3}{W} - this.addAbility(new CraftAbility("{3}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{W}")); + + // Bladewheel Chariot + + // Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, bladeWheelFilter)))); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private SpringLoadedSawblades(final SpringLoadedSawblades card) { diff --git a/Mage.Sets/src/mage/cards/s/SquallGunbladeDuelist.java b/Mage.Sets/src/mage/cards/s/SquallGunbladeDuelist.java new file mode 100644 index 00000000000..b0534bc5c43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SquallGunbladeDuelist.java @@ -0,0 +1,144 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +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.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SquallGunbladeDuelist extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(SquallGunbladeDuelistPredicate.instance); + } + + public SquallGunbladeDuelist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // As Squall enters, choose a number. + this.addAbility(new AsEntersBattlefieldAbility(new SquallGunbladeDuelistChooseEffect())); + + // Whenever one or more creatures attack one of your opponents, if any of those creatures have power or toughness equal to the chosen number, Squall deals damage equal to its power to defending player. + this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility( + new SquallGunbladeDuelistDamageEffect(), 1, + filter, SetTargetPointer.PLAYER, true + ).setTriggerPhrase("Whenever one or more creatures attack one of your opponents, " + + "if any of those creatures have power or toughness equal to the chosen number, ")); + } + + private SquallGunbladeDuelist(final SquallGunbladeDuelist card) { + super(card); + } + + @Override + public SquallGunbladeDuelist copy() { + return new SquallGunbladeDuelist(this); + } +} + +enum SquallGunbladeDuelistPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Integer number = (Integer) game + .getState() + .getValue(CardUtil.getObjectZoneString( + "chosenNumber", input.getSource().getId(), game, + input.getSource().getStackMomentSourceZCC(), true + )); + return number != null + && (input.getObject().getPower().getValue() == number + || input.getObject().getToughness().getValue() == number); + } +} + +class SquallGunbladeDuelistChooseEffect extends OneShotEffect { + + SquallGunbladeDuelistChooseEffect() { + super(Outcome.Benefit); + staticText = "choose a number"; + } + + private SquallGunbladeDuelistChooseEffect(final SquallGunbladeDuelistChooseEffect effect) { + super(effect); + } + + @Override + public SquallGunbladeDuelistChooseEffect copy() { + return new SquallGunbladeDuelistChooseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int number = player.getAmount(0, Integer.MAX_VALUE, "Choose a number", source, game); + game.getState().setValue(CardUtil.getObjectZoneString( + "chosenNumber", source.getId(), game, + source.getStackMomentSourceZCC(), false + ), number); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (permanent != null) { + permanent.addInfo("chosen number", "Chosen Number: " + number + "", game); + game.informPlayers(permanent.getLogName() + ", chosen number: " + number); + } + return true; + } +} + +class SquallGunbladeDuelistDamageEffect extends OneShotEffect { + + SquallGunbladeDuelistDamageEffect() { + super(Outcome.Benefit); + staticText = "{this} deals damage equal to its power to defending player"; + } + + private SquallGunbladeDuelistDamageEffect(final SquallGunbladeDuelistDamageEffect effect) { + super(effect); + } + + @Override + public SquallGunbladeDuelistDamageEffect copy() { + return new SquallGunbladeDuelistDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Permanent permanent = source.getSourcePermanentOrLKI(game); + return player != null + && permanent != null + && player.damage(permanent.getPower().getValue(), permanent.getId(), source, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StalkingPredator.java b/Mage.Sets/src/mage/cards/s/StalkingPredator.java deleted file mode 100644 index 41a12f42f97..00000000000 --- a/Mage.Sets/src/mage/cards/s/StalkingPredator.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.NightboundAbility; -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 StalkingPredator extends CardImpl { - - public StalkingPredator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setBlack(true); - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private StalkingPredator(final StalkingPredator card) { - super(card); - } - - @Override - public StalkingPredator copy() { - return new StalkingPredator(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StalkingVampire.java b/Mage.Sets/src/mage/cards/s/StalkingVampire.java deleted file mode 100644 index 0fc17107c6a..00000000000 --- a/Mage.Sets/src/mage/cards/s/StalkingVampire.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class StalkingVampire extends CardImpl { - - public StalkingVampire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.VAMPIRE); - this.color.setBlack(true); - - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // At the beginning of your upkeep, you may pay {2}{B}{B}. If you do, transform Stalking Vampire. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( - new TransformSourceEffect(), - new ManaCostsImpl<>("{2}{B}{B}") - ))); - } - - private StalkingVampire(final StalkingVampire card) { - super(card); - } - - @Override - public StalkingVampire copy() { - return new StalkingVampire(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StandUnited.java b/Mage.Sets/src/mage/cards/s/StandUnited.java new file mode 100644 index 00000000000..adb0aaa10ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StandUnited.java @@ -0,0 +1,66 @@ +package mage.cards.s; + +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.constants.SubType; +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 StandUnited extends CardImpl { + + public StandUnited(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G/W}"); + + // Target creature gets +2/+2 until end of turn. If it's an Ally, scry 2. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addEffect(new StandUnitedEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private StandUnited(final StandUnited card) { + super(card); + } + + @Override + public StandUnited copy() { + return new StandUnited(this); + } +} + +class StandUnitedEffect extends OneShotEffect { + + StandUnitedEffect() { + super(Outcome.Benefit); + staticText = "If it's an Ally, scry 2"; + } + + private StandUnitedEffect(final StandUnitedEffect effect) { + super(effect); + } + + @Override + public StandUnitedEffect copy() { + return new StandUnitedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return player != null && permanent != null + && permanent.hasSubtype(SubType.ALLY, game) + && player.scry(2, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java b/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java index 9000a352fdb..97050e68e24 100644 --- a/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java +++ b/Mage.Sets/src/mage/cards/s/StarscreamPowerHungry.java @@ -1,17 +1,19 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.BecomesMonarchSourceControllerTriggeredAbility; import mage.abilities.common.CombatDamageDealtToYouTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DrawCardControllerTriggeredAbility; +import mage.abilities.condition.common.MonarchIsNotSetCondition; import mage.abilities.condition.common.MonarchIsSourceControllerCondition; +import mage.abilities.effects.common.BecomesMonarchTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.hint.common.MonarchHint; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.*; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -22,31 +24,57 @@ import java.util.UUID; /** * @author Susucr */ -public final class StarscreamPowerHungry extends CardImpl { +public final class StarscreamPowerHungry extends TransformingDoubleFacedCard { public StarscreamPowerHungry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{3}{B}", + "Starscream, Seeker Leader", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.s.StarscreamSeekerLeader.class; + // Starscream, Power Hungry + this.getLeftHalfCard().setPT(2, 3); // More Than Meets the Eye {2}{B} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{B}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{B}")); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever you draw a card, if you're the monarch, target opponent loses 2 life. Ability ability = new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(2), false) .withInterveningIf(MonarchIsSourceControllerCondition.instance); ability.addTarget(new TargetOpponent()); - this.addAbility(ability.addHint(MonarchHint.instance)); + this.getLeftHalfCard().addAbility(ability.addHint(MonarchHint.instance)); // Whenever one or more creatures deal combat damage to you, convert Starscream. - this.addAbility(new CombatDamageDealtToYouTriggeredAbility( + this.getLeftHalfCard().addAbility(new CombatDamageDealtToYouTriggeredAbility( + new TransformSourceEffect().setText("convert {this}") + )); + + // Starscream, Seeker Leader + this.getRightHalfCard().setPT(2, 3); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Whenever Starscream deals combat damage to a player, if there is no monarch, that player becomes the monarch. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new BecomesMonarchTargetEffect().setText("that player becomes the monarch"), false, true + ).withInterveningIf(MonarchIsNotSetCondition.instance).addHint(MonarchHint.instance)); + + // Whenever you become the monarch, convert Starscream. + this.getRightHalfCard().addAbility(new BecomesMonarchSourceControllerTriggeredAbility( new TransformSourceEffect().setText("convert {this}") )); } diff --git a/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java b/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java deleted file mode 100644 index e8f24856628..00000000000 --- a/Mage.Sets/src/mage/cards/s/StarscreamSeekerLeader.java +++ /dev/null @@ -1,68 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.BecomesMonarchSourceControllerTriggeredAbility; -import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.condition.common.MonarchIsNotSetCondition; -import mage.abilities.effects.common.BecomesMonarchTargetEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.common.MonarchHint; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.LivingMetalAbility; -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 java.util.UUID; - -/** - * @author Susucr - */ -public final class StarscreamSeekerLeader extends CardImpl { - - public StarscreamSeekerLeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.color.setBlack(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Whenever Starscream deals combat damage to a player, if there is no monarch, that player becomes the monarch. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new BecomesMonarchTargetEffect().setText("that player becomes the monarch"), false, true - ).withInterveningIf(MonarchIsNotSetCondition.instance).addHint(MonarchHint.instance)); - - // Whenever you become the monarch, convert Starscream. - this.addAbility(new BecomesMonarchSourceControllerTriggeredAbility( - new TransformSourceEffect().setText("convert {this}") - )); - } - - private StarscreamSeekerLeader(final StarscreamSeekerLeader card) { - super(card); - } - - @Override - public StarscreamSeekerLeader copy() { - return new StarscreamSeekerLeader(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StartledAwake.java b/Mage.Sets/src/mage/cards/s/StartledAwake.java index d9e1a5b049b..d46bc468036 100644 --- a/Mage.Sets/src/mage/cards/s/StartledAwake.java +++ b/Mage.Sets/src/mage/cards/s/StartledAwake.java @@ -1,17 +1,21 @@ package mage.cards.s; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.keyword.SkulkAbility; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.cards.TransformingDoubleFacedCardHalf; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -22,22 +26,34 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class StartledAwake extends CardImpl { +public final class StartledAwake extends TransformingDoubleFacedCard { public StartledAwake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.SORCERY}, new SubType[]{}, "{2}{U}{U}", + "Persistent Nightmare", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.NIGHTMARE}, "U"); - this.secondSideCardClazz = mage.cards.p.PersistentNightmare.class; + this.getRightHalfCard().setPT(1, 1); // Target opponent puts the top thirteen cards of their library into their graveyard. - this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addEffect(new MillCardsTargetEffect(13)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetOpponent()); + this.getLeftHalfCard().getSpellAbility().addEffect(new MillCardsTargetEffect(13)); // {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( Zone.GRAVEYARD, new StartledAwakeReturnTransformedEffect(), new ManaCostsImpl<>("{3}{U}{U}") )); + + // Persistent Nightmare + + // Skulk + this.getRightHalfCard().addAbility(new SkulkAbility()); + + // When Persistent Nightmare deals combat damage to a player, return it to its owner's hand. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new ReturnToHandSourceEffect(), false + ).setTriggerPhrase("When {this} deals combat damage to a player, ")); } private StartledAwake(final StartledAwake card) { @@ -76,8 +92,12 @@ class StartledAwakeReturnTransformedEffect extends OneShotEffect { if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) { return true; } - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), true); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide(); + if (backSide == null) { + return true; + } + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true); + controller.moveCards(backSide, Zone.BATTLEFIELD, source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/StonewingAntagonizer.java b/Mage.Sets/src/mage/cards/s/StonewingAntagonizer.java deleted file mode 100644 index 31f18cbdc2b..00000000000 --- a/Mage.Sets/src/mage/cards/s/StonewingAntagonizer.java +++ /dev/null @@ -1,40 +0,0 @@ - -package mage.cards.s; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class StonewingAntagonizer extends CardImpl { - - public StonewingAntagonizer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},""); - this.subtype.add(SubType.GARGOYLE); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private StonewingAntagonizer(final StonewingAntagonizer card) { - super(card); - } - - @Override - public StonewingAntagonizer copy() { - return new StonewingAntagonizer(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java index e9efff07687..31bf8824c71 100644 --- a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java +++ b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -11,12 +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.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -66,25 +61,6 @@ class StonewiseFortifierPreventAllDamageToEffect extends PreventionEffectImpl { return new StonewiseFortifierPreventAllDamageToEffect(this); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), event.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int preventedDamage = event.getAmount(); - MageObject damageSource = game.getObject(event.getSourceId()); - MageObject preventionSource = game.getObject(source); - if (damageSource != null && preventionSource != null) { - String message = " damage from " + - damageSource.getName() + " prevented " + - '(' + preventionSource + ')'; - game.informPlayers(message); - } - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), preventedDamage)); - } - return false; - } - @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game) && event.getTargetId().equals(source.getSourceId())) { diff --git a/Mage.Sets/src/mage/cards/s/StormChargedSlasher.java b/Mage.Sets/src/mage/cards/s/StormChargedSlasher.java deleted file mode 100644 index 1da4c1b1449..00000000000 --- a/Mage.Sets/src/mage/cards/s/StormChargedSlasher.java +++ /dev/null @@ -1,60 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.NightboundAbility; -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.target.common.TargetControlledCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class StormChargedSlasher extends CardImpl { - - public StormChargedSlasher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.nightCard = true; - - // At the beginning of combat on your turn, target creature you control gets +2/+0 and gains trample and haste until end of turn. - Ability ability = new BeginningOfCombatTriggeredAbility( - new BoostTargetEffect(2, 0) - .setText("target creature you control gets +2/+0") - ); - ability.addEffect(new GainAbilityTargetEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn - ).setText("and gains trample")); - ability.addEffect(new GainAbilityTargetEffect( - HasteAbility.getInstance(), Duration.EndOfTurn - ).setText("and haste until end of turn")); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private StormChargedSlasher(final StormChargedSlasher card) { - super(card); - } - - @Override - public StormChargedSlasher copy() { - return new StormChargedSlasher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StormOfMemories.java b/Mage.Sets/src/mage/cards/s/StormOfMemories.java new file mode 100644 index 00000000000..8536d02670a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormOfMemories.java @@ -0,0 +1,141 @@ +package mage.cards.s; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.StormAbility; +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.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 mage.util.RandomUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormOfMemories extends CardImpl { + + public StormOfMemories(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{R}{R}"); + + // Storm + this.addAbility(new StormAbility()); + + // Exile an instant or sorcery card with mana value 3 or less from your graveyard at random. You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead. + this.getSpellAbility().addEffect(new StormOfMemoriesEffect()); + } + + private StormOfMemories(final StormOfMemories card) { + super(card); + } + + @Override + public StormOfMemories copy() { + return new StormOfMemories(this); + } +} + +class StormOfMemoriesEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterInstantOrSorceryCard(); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + StormOfMemoriesEffect() { + super(Outcome.Benefit); + staticText = "exile an instant or sorcery card with mana value 3 or less from your graveyard at random. " + + "You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead."; + } + + private StormOfMemoriesEffect(final StormOfMemoriesEffect effect) { + super(effect); + } + + @Override + public StormOfMemoriesEffect copy() { + return new StormOfMemoriesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = RandomUtil.randomFromCollection(player.getGraveyard().getCards(filter, game)); + return card != null && CardUtil.castSpellWithAttributesForFree( + player, source, game, new CardsImpl(card), + StaticFilters.FILTER_CARD, StormOfMemoriesTracker.instance + ); + } +} + +enum StormOfMemoriesTracker 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 StormOfMemoriesReplacementEffect(card, game), source); + } +} + +class StormOfMemoriesReplacementEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + StormOfMemoriesReplacementEffect(Card card, Game game) { + super(Duration.EndOfTurn, Outcome.Exile); + this.mor = new MageObjectReference(card.getMainCard(), game); + } + + private StormOfMemoriesReplacementEffect(final StormOfMemoriesReplacementEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public StormOfMemoriesReplacementEffect copy() { + return new StormOfMemoriesReplacementEffect(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/StormTheVault.java b/Mage.Sets/src/mage/cards/s/StormTheVault.java index a76502a82c5..b901243a79d 100644 --- a/Mage.Sets/src/mage/cards/s/StormTheVault.java +++ b/Mage.Sets/src/mage/cards/s/StormTheVault.java @@ -1,18 +1,21 @@ package mage.cards.s; +import mage.Mana; import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.mana.DynamicManaEffect; import mage.abilities.hint.common.ArtifactYouControlHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.SimpleManaAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.permanent.token.TreasureToken; @@ -21,26 +24,34 @@ import java.util.UUID; /** * @author LevelX2 */ -public final class StormTheVault extends CardImpl { +public final class StormTheVault extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledArtifactPermanent("you control five or more artifacts"), ComparisonType.MORE_THAN, 4 ); public StormTheVault(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{R}"); - - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.v.VaultOfCatlacan.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{U}{R}", + "Vault of Catlacan", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); // 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 OneOrMoreCombatDamagePlayerTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + this.getLeftHalfCard().addAbility(new OneOrMoreCombatDamagePlayerTriggeredAbility(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()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(ArtifactYouControlHint.instance)); + + // Vault of Catlacan + // {T}: Add one mana of any color. + this.getRightHalfCard().addAbility(new AnyColorManaAbility()); + + // {T}: Add {U} for each artifact you control. + this.getRightHalfCard().addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, + new DynamicManaEffect(Mana.BlueMana(1), ArtifactYouControlCount.instance), + new TapSourceCost()).addHint(ArtifactYouControlHint.instance)); } private StormTheVault(final StormTheVault card) { diff --git a/Mage.Sets/src/mage/cards/s/StormwildCapridor.java b/Mage.Sets/src/mage/cards/s/StormwildCapridor.java index edc2d3bf2fa..f3cb1458854 100644 --- a/Mage.Sets/src/mage/cards/s/StormwildCapridor.java +++ b/Mage.Sets/src/mage/cards/s/StormwildCapridor.java @@ -75,7 +75,6 @@ class StormwildCapridorEffect extends PreventionEffectImpl { if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/s/StranglingGrasp.java b/Mage.Sets/src/mage/cards/s/StranglingGrasp.java deleted file mode 100644 index e8b2b3ab4ab..00000000000 --- a/Mage.Sets/src/mage/cards/s/StranglingGrasp.java +++ /dev/null @@ -1,113 +0,0 @@ -package mage.cards.s; - -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.keyword.EnchantAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -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.filter.FilterPermanent; -import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; -import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.permanent.CanBeSacrificedPredicate; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class StranglingGrasp extends CardImpl { - - private static final FilterPermanent filter - = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - - public StranglingGrasp(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setBlack(true); - this.nightCard = true; - - // Enchant creature or planeswalker an opponent controls - TargetPermanent auraTarget = new TargetPermanent(filter); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // At the beginning of your upkeep, enchanted permanent's controller sacrifices a nonland permanent and loses 1 life. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new StranglingGraspEffect())); - } - - private StranglingGrasp(final StranglingGrasp card) { - super(card); - } - - @Override - public StranglingGrasp copy() { - return new StranglingGrasp(this); - } -} - -class StranglingGraspEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(CanBeSacrificedPredicate.instance); - } - - StranglingGraspEffect() { - super(Outcome.Benefit); - staticText = "enchanted permanent's controller sacrifices a nonland permanent, then that player loses 1 life"; - } - - private StranglingGraspEffect(final StranglingGraspEffect effect) { - super(effect); - } - - @Override - public StranglingGraspEffect copy() { - return new StranglingGraspEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = Optional - .ofNullable(source.getSourcePermanentOrLKI(game)) - .map(Permanent::getAttachedTo) - .map(game::getPermanentOrLKIBattlefield) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .orElse(null); - if (player == null) { - return false; - } - TargetPermanent target = new TargetPermanent(filter); - target.withNotTarget(true); - 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); - } - } - player.loseLife(1, game, source, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/StrionicResonator.java b/Mage.Sets/src/mage/cards/s/StrionicResonator.java index c521659aad9..72a9a53b6c0 100644 --- a/Mage.Sets/src/mage/cards/s/StrionicResonator.java +++ b/Mage.Sets/src/mage/cards/s/StrionicResonator.java @@ -8,11 +8,7 @@ import mage.abilities.effects.common.CopyTargetStackObjectEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; -import mage.filter.FilterStackObject; -import mage.filter.predicate.Predicate; -import mage.game.Game; -import mage.game.stack.StackObject; +import mage.filter.StaticFilters; import mage.target.TargetStackObject; import java.util.UUID; @@ -22,20 +18,13 @@ import java.util.UUID; */ public final class StrionicResonator extends CardImpl { - private static final FilterStackObject filter = new FilterStackObject("triggered ability you control"); - - static { - filter.add(StrionicResonatorPredicate.instance); - filter.add(TargetController.YOU.getControllerPredicate()); - } - public StrionicResonator(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {2}, {T}: Copy target triggered ability you control. You may choose new targets for the copy. Ability ability = new SimpleActivatedAbility(new CopyTargetStackObjectEffect(), new ManaCostsImpl<>("{2}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetStackObject(filter)); + ability.addTarget(new TargetStackObject(StaticFilters.FILTER_CONTROLLED_TRIGGERED_ABILITY)); this.addAbility(ability); } @@ -48,12 +37,3 @@ public final class StrionicResonator extends CardImpl { return new StrionicResonator(this); } } - -enum StrionicResonatorPredicate implements Predicate { - instance; - - @Override - public boolean apply(StackObject input, Game game) { - return input instanceof Ability && ((Ability) input).isTriggeredAbility(); - } -} diff --git a/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java b/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java index 0defbb6289f..4b03d74c4e5 100644 --- a/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java +++ b/Mage.Sets/src/mage/cards/s/StrongTheBrutishThespian.java @@ -30,7 +30,7 @@ public class StrongTheBrutishThespian extends CardImpl { this.toughness = new MageInt(7); // Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); // Enrage - Whenever Strong is dealt damage, you get three rad counters and put three +1/+1 counters on Strong. Ability enrageAbility = new DealtDamageToSourceTriggeredAbility(new AddCountersPlayersEffect(CounterType.RAD.createInstance(3), TargetController.YOU), false, true); diff --git a/Mage.Sets/src/mage/cards/s/StructuralCollapse.java b/Mage.Sets/src/mage/cards/s/StructuralCollapse.java index f95d4fd4ca8..f1f315c38b2 100644 --- a/Mage.Sets/src/mage/cards/s/StructuralCollapse.java +++ b/Mage.Sets/src/mage/cards/s/StructuralCollapse.java @@ -26,7 +26,7 @@ public final class StructuralCollapse extends CardImpl { .setText("target player sacrifices an artifact")); this.getSpellAbility().addEffect(new SacrificeEffect(StaticFilters.FILTER_LANDS, 1, "Target player") .setText("and a land of their choice")); - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "that player")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("that player")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/s/SuddenShock.java b/Mage.Sets/src/mage/cards/s/SuddenShock.java index 4d989df4170..0d0db16afc5 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenShock.java +++ b/Mage.Sets/src/mage/cards/s/SuddenShock.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.SplitSecondAbility; import mage.cards.CardImpl; @@ -9,6 +7,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * * @author LevelX2 @@ -18,11 +18,11 @@ public final class SuddenShock extends CardImpl { public SuddenShock(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); - // Split second this.addAbility(new SplitSecondAbility()); + // Sudden Shock deals 2 damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true)); + this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/s/SukiCourageousRescuer.java b/Mage.Sets/src/mage/cards/s/SukiCourageousRescuer.java new file mode 100644 index 00000000000..ffbbf87e5f6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SukiCourageousRescuer.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +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.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SukiCourageousRescuer extends CardImpl { + + public SukiCourageousRescuer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Other creatures you control get +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, true + ))); + + // Whenever another permanent you control leaves the battlefield during your turn, create a 1/1 white Ally creature token. This ability triggers only once each turn. + this.addAbility(new LeavesBattlefieldAllTriggeredAbility( + new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_CONTROLLED_ANOTHER_PERMANENT + ).withTriggerCondition(MyTurnCondition.instance).setTriggersLimitEachTurn(1)); + } + + private SukiCourageousRescuer(final SukiCourageousRescuer card) { + super(card); + } + + @Override + public SukiCourageousRescuer copy() { + return new SukiCourageousRescuer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SukiKyoshiCaptain.java b/Mage.Sets/src/mage/cards/s/SukiKyoshiCaptain.java new file mode 100644 index 00000000000..f9c1b602a33 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SukiKyoshiCaptain.java @@ -0,0 +1,63 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +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 mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SukiKyoshiCaptain extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.WARRIOR, "Warriors"); + private static final FilterPermanent filter2 = new FilterPermanent(SubType.WARRIOR, "attacking Warriors"); + + static { + filter.add(AttackingPredicate.instance); + } + + public SukiKyoshiCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Other Warriors you control get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + ))); + + // {3}{W}: Attacking Warriors you control gain double strike until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, filter2 + ), new ManaCostsImpl<>("{3}{W}"))); + } + + private SukiKyoshiCaptain(final SukiKyoshiCaptain card) { + super(card); + } + + @Override + public SukiKyoshiCaptain copy() { + return new SukiKyoshiCaptain(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SulfuricVortex.java b/Mage.Sets/src/mage/cards/s/SulfuricVortex.java index caadd18288e..095760ee847 100644 --- a/Mage.Sets/src/mage/cards/s/SulfuricVortex.java +++ b/Mage.Sets/src/mage/cards/s/SulfuricVortex.java @@ -28,7 +28,7 @@ public final class SulfuricVortex extends CardImpl { // At the beginning of each player's upkeep, Sulfuric Vortex deals 2 damage to that player. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(2, true, "that player"), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(TargetController.EACH_PLAYER, new DamageTargetEffect(2).withTargetDescription("that player"), false)); // If a player would gain life, that player gains no life instead. this.addAbility(new SimpleStaticAbility(new SulfuricVortexReplacementEffect())); diff --git a/Mage.Sets/src/mage/cards/s/SummonAlexander.java b/Mage.Sets/src/mage/cards/s/SummonAlexander.java deleted file mode 100644 index 6a752a4b835..00000000000 --- a/Mage.Sets/src/mage/cards/s/SummonAlexander.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.common.PreventAllDamageToAllEffect; -import mage.abilities.effects.common.TapAllEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SummonAlexander extends CardImpl { - - public SummonAlexander(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setWhite(true); - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I, II -- Prevent all damage that would be dealt to creatures you control this turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, - new PreventAllDamageToAllEffect( - Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED - ) - ); - - // III -- Tap all creatures your opponents control. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES) - ); - this.addAbility(sagaAbility.withShowSacText(true)); - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private SummonAlexander(final SummonAlexander card) { - super(card); - } - - @Override - public SummonAlexander copy() { - return new SummonAlexander(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java b/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java index c78cc9eb20d..c8328f7f9a0 100644 --- a/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java +++ b/Mage.Sets/src/mage/cards/s/SummonBrynhildr.java @@ -139,12 +139,17 @@ class SummonBrynhildrWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() != GameEvent.EventType.COUNTER_ADDED - || !CounterType.STUN.getName().equals(event.getData())) { + || !CounterType.LORE.getName().equals(event.getData())) { return; } Permanent permanent = game.getPermanent(event.getTargetId()); + int offset = 0; + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + offset++; + } if (permanent != null) { - map.computeIfAbsent(new MageObjectReference(permanent, game), x -> new HashSet<>()) + map.computeIfAbsent(new MageObjectReference(permanent, game, offset), x -> new HashSet<>()) .add(event.getPlayerId()); } } diff --git a/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java b/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java deleted file mode 100644 index a8015ec0963..00000000000 --- a/Mage.Sets/src/mage/cards/s/SummonEsperMaduin.java +++ /dev/null @@ -1,103 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.CardsImpl; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SummonEsperMaduin extends CardImpl { - - public SummonEsperMaduin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SAGA); - this.subtype.add(SubType.ELEMENTAL); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.nightCard = true; - this.color.setGreen(true); - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Reveal the top card of your library. If it's a permanent card, put it into your hand. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new SummonEsperMaduinEffect()); - - // II -- Add {G}{G}. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new BasicManaEffect(Mana.GreenMana(2))); - - // III -- Other creatures you control get +2/+2 and gain trample until end of turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new BoostControlledEffect( - 2, 2, Duration.EndOfTurn, true - ).setText("other creatures you control get +2/+2"), - new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE, true - ).setText("and gain trample until end of turn") - ); - this.addAbility(sagaAbility.withShowSacText(true)); - } - - private SummonEsperMaduin(final SummonEsperMaduin card) { - super(card); - } - - @Override - public SummonEsperMaduin copy() { - return new SummonEsperMaduin(this); - } -} - -class SummonEsperMaduinEffect extends OneShotEffect { - - SummonEsperMaduinEffect() { - super(Outcome.Benefit); - staticText = "reveal the top card of your library. If it's a permanent card, put it into your hand"; - } - - private SummonEsperMaduinEffect(final SummonEsperMaduinEffect effect) { - super(effect); - } - - @Override - public SummonEsperMaduinEffect copy() { - return new SummonEsperMaduinEffect(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.revealCards(source, new CardsImpl(card), game); - if (card.isPermanent(game)) { - player.moveCards(card, Zone.HAND, source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java b/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java index 3a2c1b4614a..3fcc14c2c8e 100644 --- a/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java +++ b/Mage.Sets/src/mage/cards/s/SummonEsperValigarmanda.java @@ -107,7 +107,7 @@ class SummonEsperValigarmandaExileEffect extends OneShotEffect { return !cards.isEmpty() && controller.moveCardsToExile( cards.getCards(game), source, game, true, - CardUtil.getExileZoneId(game, source, 1), + CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source) ); } diff --git a/Mage.Sets/src/mage/cards/s/SunBlessedGuardian.java b/Mage.Sets/src/mage/cards/s/SunBlessedGuardian.java index 4a19774bc99..07a58693e57 100644 --- a/Mage.Sets/src/mage/cards/s/SunBlessedGuardian.java +++ b/Mage.Sets/src/mage/cards/s/SunBlessedGuardian.java @@ -1,34 +1,46 @@ package mage.cards.s; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; import java.util.UUID; /** * @author TheElk801 */ -public final class SunBlessedGuardian extends CardImpl { +public final class SunBlessedGuardian extends TransformingDoubleFacedCard { public SunBlessedGuardian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{1}{W}", + "Furnace-Blessed Conqueror", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.CLERIC}, "WR" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.f.FurnaceBlessedConqueror.class; + // Sun-Blessed Guardian + this.getLeftHalfCard().setPT(2, 2); // {5}{R/P}: Transform Sun-Blessed Guardian. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R/P}"))); + + // Furnace-Blessed Conqueror + this.getRightHalfCard().setPT(3, 3); + + // Whenever Furnace-Blessed Conqueror attacks, create a tapped and attacking token that's a copy of it. Put a +1/+1 counter on that token for each +1/+1 counter on Furnace-Blessed Conqueror. Sacrifice that token at the beginning of the next end step. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new SunBlessedGuardianEffect())); } private SunBlessedGuardian(final SunBlessedGuardian card) { @@ -40,3 +52,44 @@ public final class SunBlessedGuardian extends CardImpl { return new SunBlessedGuardian(this); } } + +class SunBlessedGuardianEffect extends OneShotEffect { + + SunBlessedGuardianEffect() { + super(Outcome.Benefit); + staticText = "create a tapped and attacking token that's a copy of it. " + + "Put a +1/+1 counter on that token for each +1/+1 counter on {this}. " + + "Sacrifice that token at the beginning of the next end step"; + } + + private SunBlessedGuardianEffect(final SunBlessedGuardianEffect effect) { + super(effect); + } + + @Override + public SunBlessedGuardianEffect copy() { + return new SunBlessedGuardianEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( + null, null, false, 1, true, true + ); + effect.setSavedPermanent(permanent); + effect.apply(game, source); + effect.sacrificeTokensCreatedAtNextEndStep(game, source); + int counters = permanent.getCounters(game).getCount(CounterType.P1P1); + if (counters < 1) { + return true; + } + for (Permanent token : effect.getAddedPermanents()) { + token.addCounters(CounterType.P1P1.createInstance(counters), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunBlessedPeak.java b/Mage.Sets/src/mage/cards/s/SunBlessedPeak.java new file mode 100644 index 00000000000..252a264483e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunBlessedPeak.java @@ -0,0 +1,48 @@ +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.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.RedManaAbility; +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 SunBlessedPeak extends CardImpl { + + public SunBlessedPeak(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // This land enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {R} or {W}. + this.addAbility(new RedManaAbility()); + this.addAbility(new WhiteManaAbility()); + + // {4}, {T}, Sacrifice this land: Draw a card. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private SunBlessedPeak(final SunBlessedPeak card) { + super(card); + } + + @Override + public SunBlessedPeak copy() { + return new SunBlessedPeak(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunWarriors.java b/Mage.Sets/src/mage/cards/s/SunWarriors.java new file mode 100644 index 00000000000..1d7e33d3f4f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunWarriors.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SunWarriors extends CardImpl { + + public SunWarriors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Firebending X, where X is the number of creatures you control. + this.addAbility(new FirebendingAbility(CreaturesYouControlCount.PLURAL)); + + // {5}: Create a 1/1 white Ally creature token. + this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new AllyToken()), new GenericManaCost(5))); + } + + private SunWarriors(final SunWarriors card) { + super(card); + } + + @Override + public SunWarriors copy() { + return new SunWarriors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunbirdEffigy.java b/Mage.Sets/src/mage/cards/s/SunbirdEffigy.java deleted file mode 100644 index f037f12199c..00000000000 --- a/Mage.Sets/src/mage/cards/s/SunbirdEffigy.java +++ /dev/null @@ -1,192 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.Mana; -import mage.ObjectColor; -import mage.abilities.Ability; -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.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.effects.mana.ManaEffect; -import mage.abilities.hint.Hint; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.ExileZone; -import mage.game.Game; -import mage.util.CardUtil; - -import java.util.Objects; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author TheElk801 - */ -public final class SunbirdEffigy extends CardImpl { - - public SunbirdEffigy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.BIRD); - this.subtype.add(SubType.CONSTRUCT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Sunbird Effigy's power and toughness are each equal to the number of colors among the exiled cards used to craft it. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SetBasePowerToughnessSourceEffect(SunbirdEffigyValue.instance) - ).addHint(SunbirdEffigyHint.instance)); - - // {T}: For each color among the exiled cards used to craft Sunbird Effigy, add one mana of that color. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new SunbirdEffigyEffect(), new TapSourceCost())); - } - - private SunbirdEffigy(final SunbirdEffigy card) { - super(card); - } - - @Override - public SunbirdEffigy copy() { - return new SunbirdEffigy(this); - } -} - -enum SunbirdEffigyValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - return Optional - .ofNullable(getColor(game, sourceAbility)) - .filter(Objects::nonNull) - .map(ObjectColor::getColorCount) - .orElse(0); - } - - @Override - public SunbirdEffigyValue copy() { - return this; - } - - @Override - public String getMessage() { - return "colors among the exiled cards used to craft it"; - } - - @Override - public String toString() { - return "1"; - } - - static ObjectColor getColor(Game game, Ability source) { - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, - source.getSourceId(), - game.getState().getZoneChangeCounter(source.getSourceId()) - 2 - )); - return exileZone == null ? null : exileZone - .getCards(game) - .stream() - .map(card -> card.getColor(game)) - .reduce(new ObjectColor(), ObjectColor::union); - } -} - -enum SunbirdEffigyHint implements Hint { - instance; - - @Override - public String getText(Game game, Ability ability) { - ObjectColor color = SunbirdEffigyValue.getColor(game, ability); - if (color == null) { - return null; - } - if (color.isColorless()) { - return "No colors among exiled cards."; - } - return color - .getColors() - .stream() - .map(ObjectColor::getDescription) - .collect(Collectors.joining(", ", "Colors among exiled cards: ", "")); - } - - @Override - public Hint copy() { - return this; - } -} - -class SunbirdEffigyEffect extends ManaEffect { - - SunbirdEffigyEffect() { - super(); - staticText = "for each color among the exiled cards used to craft {this}, add one mana of that color"; - } - - private SunbirdEffigyEffect(final SunbirdEffigyEffect effect) { - super(effect); - } - - @Override - public SunbirdEffigyEffect copy() { - return new SunbirdEffigyEffect(this); - } - - @Override - public Mana produceMana(Game game, Ability source) { - Mana mana = new Mana(); - if (game == null) { - return mana; - } - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId(game, source, -2)); - if (exileZone == null) { - return mana; - } - ObjectColor color = exileZone - .getCards(game) - .stream() - .map(card -> card.getColor(game)) - .reduce(new ObjectColor(), ObjectColor::union); - if (color.isWhite()) { - mana.increaseWhite(); - } - if (color.isBlue()) { - mana.increaseBlue(); - } - if (color.isBlack()) { - mana.increaseBlack(); - } - if (color.isRed()) { - mana.increaseRed(); - } - if (color.isGreen()) { - mana.increaseGreen(); - } - return mana; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SunbirdStandard.java b/Mage.Sets/src/mage/cards/s/SunbirdStandard.java index 0f82aa34aa4..55c7f85665b 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdStandard.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdStandard.java @@ -1,30 +1,76 @@ package mage.cards.s; +import mage.Mana; +import mage.ObjectColor; +import mage.abilities.Ability; +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.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.effects.mana.ManaEffect; +import mage.abilities.hint.Hint; import mage.abilities.keyword.CraftAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 */ -public final class SunbirdStandard extends CardImpl { +public final class SunbirdStandard extends TransformingDoubleFacedCard { public SunbirdStandard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - this.secondSideCardClazz = mage.cards.s.SunbirdEffigy.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}", + "Sunbird Effigy", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.BIRD, SubType.CONSTRUCT}, "" + ); // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); + this.getLeftHalfCard().addAbility(new AnyColorManaAbility()); // Craft with one or more {5} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{5}", "one or more", "other permanents " + "you control and/or cards in your graveyard", 1, Integer.MAX_VALUE )); + + // Sunbird Effigy + this.getRightHalfCard().setPT(0, 0); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Sunbird Effigy's power and toughness are each equal to the number of colors among the exiled cards used to craft it. + this.getRightHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, new SetBasePowerToughnessSourceEffect(SunbirdEffigyValue.instance) + ).addHint(SunbirdEffigyHint.instance)); + + // {T}: For each color among the exiled cards used to craft Sunbird Effigy, add one mana of that color. + this.getRightHalfCard().addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new SunbirdEffigyEffect(), new TapSourceCost())); } private SunbirdStandard(final SunbirdStandard card) { @@ -36,3 +82,132 @@ public final class SunbirdStandard extends CardImpl { return new SunbirdStandard(this); } } + +enum SunbirdEffigyValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional + .ofNullable(getColor(game, sourceAbility)) + .filter(Objects::nonNull) + .map(ObjectColor::getColorCount) + .orElse(0); + } + + @Override + public SunbirdEffigyValue copy() { + return this; + } + + @Override + public String getMessage() { + return "colors among the exiled cards used to craft it"; + } + + @Override + public String toString() { + return "1"; + } + + static ObjectColor getColor(Game game, Ability source) { + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard == null) { + return null; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, + sourceCard.getMainCard().getId(), + sourceCard.getMainCard().getZoneChangeCounter(game) - 1 + )); + return exileZone == null ? null : exileZone + .getCards(game) + .stream() + .map(card -> card.getColor(game)) + .reduce(new ObjectColor(), ObjectColor::union); + } +} + +enum SunbirdEffigyHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + ObjectColor color = SunbirdEffigyValue.getColor(game, ability); + if (color == null) { + return null; + } + if (color.isColorless()) { + return "No colors among exiled cards."; + } + return color + .getColors() + .stream() + .map(ObjectColor::getDescription) + .collect(Collectors.joining(", ", "Colors among exiled cards: ", "")); + } + + @Override + public Hint copy() { + return this; + } +} + +class SunbirdEffigyEffect extends ManaEffect { + + SunbirdEffigyEffect() { + super(); + staticText = "for each color among the exiled cards used to craft {this}, add one mana of that color"; + } + + private SunbirdEffigyEffect(final SunbirdEffigyEffect effect) { + super(effect); + } + + @Override + public SunbirdEffigyEffect copy() { + return new SunbirdEffigyEffect(this); + } + + @Override + public Mana produceMana(Game game, Ability source) { + Mana mana = new Mana(); + if (game == null) { + return mana; + } + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard == null) { + return mana; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId(game, sourceCard.getMainCard().getId(), + sourceCard.getMainCard().getZoneChangeCounter(game) - 1)); + if (exileZone == null) { + return mana; + } + ObjectColor color = exileZone + .getCards(game) + .stream() + .map(card -> card.getColor(game)) + .reduce(new ObjectColor(), ObjectColor::union); + if (color.isWhite()) { + mana.increaseWhite(); + } + if (color.isBlue()) { + mana.increaseBlue(); + } + if (color.isBlack()) { + mana.increaseBlack(); + } + if (color.isRed()) { + mana.increaseRed(); + } + if (color.isGreen()) { + mana.increaseGreen(); + } + return mana; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunflareShaman.java b/Mage.Sets/src/mage/cards/s/SunflareShaman.java index 70e6d1ada1a..31a468e6fa8 100644 --- a/Mage.Sets/src/mage/cards/s/SunflareShaman.java +++ b/Mage.Sets/src/mage/cards/s/SunflareShaman.java @@ -1,26 +1,24 @@ - 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.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageSelfEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndSelfEffect; 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.TargetAnyTarget; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -60,7 +58,7 @@ class SunflareShamanEffect extends OneShotEffect { filter.add(SubType.ELEMENTAL.getPredicate()); } - public SunflareShamanEffect() { + SunflareShamanEffect() { super(Outcome.Damage); this.staticText = "{this} deals X damage to any target and X damage to itself, where X is the number of Elemental cards in your graveyard"; } @@ -78,9 +76,8 @@ class SunflareShamanEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int ElementalsInYourGraveyard = controller.getGraveyard().count(filter, game); - new DamageTargetEffect(ElementalsInYourGraveyard).apply(game, source); - new DamageSelfEffect(ElementalsInYourGraveyard).apply(game, source); + int amount = controller.getGraveyard().count(filter, game); + new DamageTargetAndSelfEffect(amount, amount).apply(game, source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/s/SuperShredder.java b/Mage.Sets/src/mage/cards/s/SuperShredder.java new file mode 100644 index 00000000000..d76f9999635 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuperShredder.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuperShredder extends CardImpl { + + public SuperShredder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.MUTANT); + this.subtype.add(SubType.NINJA); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever another permanent leaves the battlefield, put a +1/+1 counter on Super Shredder. + this.addAbility(new LeavesBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_PERMANENT + )); + } + + private SuperShredder(final SuperShredder card) { + super(card); + } + + @Override + public SuperShredder copy() { + return new SuperShredder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SuperSkrull.java b/Mage.Sets/src/mage/cards/s/SuperSkrull.java new file mode 100644 index 00000000000..3786fc5d88b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuperSkrull.java @@ -0,0 +1,71 @@ +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.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +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.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.WallColorlessToken; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuperSkrull extends CardImpl { + + public SuperSkrull(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SKRULL); + this.subtype.add(SubType.SHAPESHIFTER); + this.subtype.add(SubType.VILLAIN); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{W}: Create a 0/4 colorless Wall creature token with defender. + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new WallColorlessToken()), new ManaCostsImpl<>("{2}{W}") + )); + + // {3}{G}: Super-Skrull gets +4/+4 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(4, 4, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{G}") + )); + + // {4}{R}: Super-Skrull deals 4 damage to target creature. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(4), new ManaCostsImpl<>("{4}{R}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // {5}{U}: Target player draws four cards. + ability = new SimpleActivatedAbility(new DrawCardTargetEffect(4), new ManaCostsImpl<>("{5}{U}")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private SuperSkrull(final SuperSkrull card) { + super(card); + } + + @Override + public SuperSkrull copy() { + return new SuperSkrull(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java b/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java index 1e7959688c6..d3224526610 100644 --- a/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java +++ b/Mage.Sets/src/mage/cards/s/SuperiorSpiderMan.java @@ -41,7 +41,8 @@ public final class SuperiorSpiderMan extends CardImpl { this.toughness = new MageInt(4); // Mind Swap -- You may have Superior Spider-Man enter as a copy of any creature card in a graveyard, except his name is Superior Spider-Man and he's a 4/4 Spider Human Hero in addition to his other types. When you do, exile that card. - this.addAbility(new EntersBattlefieldAbility(new SuperiorSpiderManCopyEffect(), true)); + this.addAbility(new EntersBattlefieldAbility(new SuperiorSpiderManCopyEffect(), true) + .withFlavorWord("Mind Swap")); } private SuperiorSpiderMan(final SuperiorSpiderMan card) { diff --git a/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java b/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java new file mode 100644 index 00000000000..962e1feb9d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SurgicalSuiteHospitalRoom.java @@ -0,0 +1,68 @@ +package mage.cards.s; + +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetAttackingCreature; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author oscscull + */ +public final class SurgicalSuiteHospitalRoom extends RoomCard { + + private static final FilterCard filter = new FilterCreatureCard( + "creature card with mana value 3 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public SurgicalSuiteHospitalRoom(UUID ownerId, CardSetInfo setInfo) { + // Surgical Suite + // {1}{W} + // When you unlock this door, return target creature card with mana value 3 or + // less from your graveyard to the battlefield. + // Hospital Room + // {3}{W} + // Enchantment -- Room + // Whenever you attack, put a +1/+1 counter on target attacking creature. + super(ownerId, setInfo, + "{1}{W}", "{3}{W}"); + this.subtype.add(SubType.ROOM); + + // Left half ability - "When you unlock this door, return target creature card with mana value 3 or less from your graveyard to the battlefield." + UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false, true); + left.addTarget(new TargetCardInYourGraveyard(filter)); + this.getLeftHalfCard().addAbility(left); + + // Right half ability - "Whenever you attack, put a +1/+1 counter on target attacking creature." + AttacksWithCreaturesTriggeredAbility right = new AttacksWithCreaturesTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1 + ); + right.addTarget(new TargetAttackingCreature()); + this.getRightHalfCard().addAbility(right); + + } + + private SurgicalSuiteHospitalRoom(final SurgicalSuiteHospitalRoom card) { + super(card); + } + + @Override + public SurgicalSuiteHospitalRoom copy() { + return new SurgicalSuiteHospitalRoom(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SuspiciousStowaway.java b/Mage.Sets/src/mage/cards/s/SuspiciousStowaway.java index a72eb131ce4..d06b0b02f89 100644 --- a/Mage.Sets/src/mage/cards/s/SuspiciousStowaway.java +++ b/Mage.Sets/src/mage/cards/s/SuspiciousStowaway.java @@ -1,12 +1,13 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,28 +16,42 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SuspiciousStowaway extends CardImpl { +public final class SuspiciousStowaway extends TransformingDoubleFacedCard { public SuspiciousStowaway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE, SubType.WEREWOLF}, "{1}{U}", + "Seafaring Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.SeafaringWerewolf.class; + // Suspicious Stowaway + this.getLeftHalfCard().setPT(1, 1); // Suspicious Stowaway can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); + this.getLeftHalfCard().addAbility(new CantBeBlockedSourceAbility()); // Whenever Suspicious Stowaway deals combat damage to a player, draw a card, then discard a card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new DrawDiscardControllerEffect(1, 1), false )); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Seafaring Werewolf + this.getRightHalfCard().setPT(2, 1); + + // Seafaring Werewolf can't be blocked. + this.getRightHalfCard().addAbility(new CantBeBlockedSourceAbility()); + + // Whenever Seafaring Werewolf deals combat damage to a player, draw a card. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private SuspiciousStowaway(final SuspiciousStowaway card) { diff --git a/Mage.Sets/src/mage/cards/s/Swampbenders.java b/Mage.Sets/src/mage/cards/s/Swampbenders.java new file mode 100644 index 00000000000..f7df97e858a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Swampbenders.java @@ -0,0 +1,90 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Swampbenders extends CardImpl { + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount( + new FilterPermanent(SubType.SWAMP, "Swamps on the battlefield") + ); + + public Swampbenders(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Swampbenders's power and toughness are each equal to the number of Swamps on the battlefield. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(xValue))); + + // Lands you control are Swamps in addition to their other types. + this.addAbility(new SimpleStaticAbility(new SwampbendersEffect())); + } + + private Swampbenders(final Swampbenders card) { + super(card); + } + + @Override + public Swampbenders copy() { + return new Swampbenders(this); + } +} + +class SwampbendersEffect extends ContinuousEffectImpl { + + SwampbendersEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.AIDontUseIt); + staticText = "lands you control are Swamps in addition to their other types."; + this.dependendToTypes.add(DependencyType.BecomeNonbasicLand); + this.dependencyTypes.add(DependencyType.BecomeSwamp); + } + + private SwampbendersEffect(final SwampbendersEffect effect) { + super(effect); + } + + @Override + public SwampbendersEffect copy() { + return new SwampbendersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Ability ability = new BlackManaAbility(); + for (Permanent land : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_LAND, source.getControllerId(), game + )) { + // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects + // So the ability removing has to be done before Layer 6 + // Lands have their mana ability intrinsically, so that is added in layer 4 + land.addSubType(game, SubType.SWAMP); + if (!land.getAbilities().containsRule(ability)) { + land.addAbility(ability, source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpectralBinding.java b/Mage.Sets/src/mage/cards/s/SwampsnareTrap.java similarity index 52% rename from Mage.Sets/src/mage/cards/s/SpectralBinding.java rename to Mage.Sets/src/mage/cards/s/SwampsnareTrap.java index 89d2a0f443a..7b89640e7a9 100644 --- a/Mage.Sets/src/mage/cards/s/SpectralBinding.java +++ b/Mage.Sets/src/mage/cards/s/SwampsnareTrap.java @@ -1,15 +1,19 @@ package mage.cards.s; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.keyword.DisturbAbility; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; 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.constants.Zone; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -18,14 +22,19 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SpectralBinding extends CardImpl { +public final class SwampsnareTrap extends CardImpl { - public SpectralBinding(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); + private static final Condition condition = new SourceTargetsPermanentCondition(StaticFilters.FILTER_CREATURE_FLYING); + + public SwampsnareTrap(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); this.subtype.add(SubType.AURA); - this.color.setBlue(true); - this.nightCard = true; + + // This spell costs {1} less to cast if it targets a creature with flying. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(1, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); @@ -33,19 +42,16 @@ public final class SpectralBinding extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget)); - // Enchanted creature gets -2/-0. - this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-2, 0))); - - // If Spectral Binding would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); + // Enchanted creature gets -5/-3. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-5, -3))); } - private SpectralBinding(final SpectralBinding card) { + private SwampsnareTrap(final SwampsnareTrap card) { super(card); } @Override - public SpectralBinding copy() { - return new SpectralBinding(this); + public SwampsnareTrap copy() { + return new SwampsnareTrap(this); } } diff --git a/Mage.Sets/src/mage/cards/s/Swelter.java b/Mage.Sets/src/mage/cards/s/Swelter.java index 946e3ddbf1b..e1dd60adffc 100644 --- a/Mage.Sets/src/mage/cards/s/Swelter.java +++ b/Mage.Sets/src/mage/cards/s/Swelter.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -18,7 +17,7 @@ public final class Swelter extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); // Swelter deals 2 damage to each of two target creatures. - this.getSpellAbility().addEffect(new DamageTargetEffect(2, true, "each of two target creatures")); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).withTargetDescription("each of two target creatures")); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2, 2)); } diff --git a/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java b/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java index 1a12aa1277a..5abbfe7fad8 100644 --- a/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SwordCoastSerpent.java @@ -1,9 +1,8 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; @@ -11,13 +10,8 @@ import mage.cards.AdventureCard; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.Game; -import mage.game.stack.Spell; import mage.target.common.TargetCreaturePermanent; -import mage.watchers.common.SpellsCastWatcher; -import java.util.List; -import java.util.Objects; import java.util.UUID; /** @@ -35,9 +29,9 @@ public final class SwordCoastSerpent extends AdventureCard { // Sword Coast Serpent can't be blocked as long as you've cast a noncreature spell this turn. this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( - new CantBeBlockedSourceEffect(), SwordCoastSerpentCondition.instance, + new CantBeBlockedSourceEffect(), CastNoncreatureSpellThisTurnCondition.instance, "{this} can't be blocked as long as you've cast a noncreature spell this turn" - ))); + )).addHint(CastNoncreatureSpellThisTurnCondition.getHint())); // Capsizing Wave // Return target creature to its owner's hand. @@ -56,20 +50,3 @@ public final class SwordCoastSerpent extends AdventureCard { return new SwordCoastSerpent(this); } } - -enum SwordCoastSerpentCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); - if (watcher == null) { - return false; - } - List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); - return spells != null && spells - .stream() - .filter(Objects::nonNull) - .anyMatch(spell -> !spell.isCreature(game)); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SyggWanderbrineShield.java b/Mage.Sets/src/mage/cards/s/SyggWanderbrineShield.java deleted file mode 100644 index 23165237f4d..00000000000 --- a/Mage.Sets/src/mage/cards/s/SyggWanderbrineShield.java +++ /dev/null @@ -1,69 +0,0 @@ -package mage.cards.s; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.CantBeBlockedSourceAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -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.filter.predicate.mageobject.ColorlessPredicate; -import mage.target.common.TargetControlledCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class SyggWanderbrineShield extends CardImpl { - - private static final FilterCard filter = new FilterCard("each color"); - - static { - filter.add(Predicates.not(ColorlessPredicate.instance)); - } - - public SyggWanderbrineShield(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.MERFOLK); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setWhite(true); - this.nightCard = true; - - // Sygg can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); - - // Whenever this creature transforms into Sygg, Wanderbrine Shield, target creature you control gains protection from each color until your next turn. - Ability ability = new TransformIntoSourceTriggeredAbility(new GainAbilityTargetEffect(new ProtectionAbility(filter))); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); - - // At the beginning of your first main phase, you may pay {U}. If you do, transform Sygg. - this.addAbility(new BeginningOfFirstMainTriggeredAbility( - new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{U}")) - )); - } - - private SyggWanderbrineShield(final SyggWanderbrineShield card) { - super(card); - } - - @Override - public SyggWanderbrineShield copy() { - return new SyggWanderbrineShield(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SyggWanderwineWisdom.java b/Mage.Sets/src/mage/cards/s/SyggWanderwineWisdom.java index fed8ae5083f..74481c8d303 100644 --- a/Mage.Sets/src/mage/cards/s/SyggWanderwineWisdom.java +++ b/Mage.Sets/src/mage/cards/s/SyggWanderwineWisdom.java @@ -1,8 +1,8 @@ package mage.cards.s; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerOrPlaneswalkerTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.TransformsOrEntersTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; @@ -10,14 +10,18 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.CantBeBlockedSourceAbility; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.ProtectionAbility; import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -25,20 +29,26 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class SyggWanderwineWisdom extends CardImpl { +public final class SyggWanderwineWisdom extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("each color"); + + static { + filter.add(Predicates.not(ColorlessPredicate.instance)); + } public SyggWanderwineWisdom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MERFOLK, SubType.WIZARD}, "{1}{U}", + "Sygg, Wanderbrine Shield", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MERFOLK, SubType.ROGUE}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.MERFOLK); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.s.SyggWanderbrineShield.class; + // Sygg, Wanderwine Wisdom + this.getLeftHalfCard().setPT(2, 2); // Sygg can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); + this.getLeftHalfCard().addAbility(new CantBeBlockedSourceAbility()); // Whenever this creature enters or transforms into Sygg, Wanderwine Wisdom, target creature gains "Whenever this creature deals combat damage to a player or planeswalker, draw a card" until end of turn. Ability ability = new TransformsOrEntersTriggeredAbility(new GainAbilityTargetEffect( @@ -47,13 +57,28 @@ public final class SyggWanderwineWisdom extends CardImpl { ), Duration.EndOfTurn ), false); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your first main phase, you may pay {W}. If you do, transform Sygg. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfFirstMainTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility( new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{W}")) )); + + // Sygg, Wanderbrine Shield + this.getRightHalfCard().setPT(2, 2); + + // Sygg can't be blocked. + this.getRightHalfCard().addAbility(new CantBeBlockedSourceAbility()); + + // Whenever this creature transforms into Sygg, Wanderbrine Shield, target creature you control gains protection from each color until your next turn. + Ability ability2 = new TransformIntoSourceTriggeredAbility(new GainAbilityTargetEffect(new ProtectionAbility(filter), Duration.UntilYourNextTurn)); + ability2.addTarget(new TargetControlledCreaturePermanent()); + this.getRightHalfCard().addAbility(ability2); + + // At the beginning of your first main phase, you may pay {U}. If you do, transform Sygg. + this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility( + new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{U}")) + )); } private SyggWanderwineWisdom(final SyggWanderwineWisdom card) { diff --git a/Mage.Sets/src/mage/cards/s/SynchronizedSpellcraft.java b/Mage.Sets/src/mage/cards/s/SynchronizedSpellcraft.java index 1a4e756ff70..699427c2482 100644 --- a/Mage.Sets/src/mage/cards/s/SynchronizedSpellcraft.java +++ b/Mage.Sets/src/mage/cards/s/SynchronizedSpellcraft.java @@ -3,15 +3,13 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.PartyCount; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.abilities.hint.common.PartyCountHint; 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.players.Player; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -25,7 +23,6 @@ public final class SynchronizedSpellcraft extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Synchronized Spellcraft deals 4 damage to target creature and X damage to that creature's controller, where X is the number of creatures in your party. - this.getSpellAbility().addEffect(new DamageTargetEffect(4)); this.getSpellAbility().addEffect(new SynchronizedSpellcraftEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addHint(PartyCountHint.instance); @@ -45,7 +42,8 @@ class SynchronizedSpellcraftEffect extends OneShotEffect { SynchronizedSpellcraftEffect() { super(Outcome.Benefit); - staticText = "and X damage to that creature's controller, " + + staticText = "{this} deals 4 damage to target creature " + + "and X damage to that creature's controller, " + "where X is the number of creatures in your party. " + PartyCount.getReminder(); } @@ -60,18 +58,7 @@ class SynchronizedSpellcraftEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int partyCount = PartyCount.instance.calculate(game, source, this); - if (partyCount < 1) { - return false; - } - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); - if (permanent == null) { - return false; - } - Player player = game.getPlayer(permanent.getControllerId()); - if (player == null) { - return false; - } - return player.damage(partyCount, source.getSourceId(), source, game) > 0; + int amount = PartyCount.instance.calculate(game, source, this); + return new DamageTargetAndTargetControllerEffect(4, amount).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/s/SyrVondamSunstarExemplar.java b/Mage.Sets/src/mage/cards/s/SyrVondamSunstarExemplar.java index 7f8662a830d..d08d37f22e7 100644 --- a/Mage.Sets/src/mage/cards/s/SyrVondamSunstarExemplar.java +++ b/Mage.Sets/src/mage/cards/s/SyrVondamSunstarExemplar.java @@ -105,7 +105,7 @@ class SyrVondamSunstarExemplarFirstTriggeredAbility extends TriggeredAbilityImpl class SyrVondamSunstarExemplarSecondTriggeredAbility extends TriggeredAbilityImpl { SyrVondamSunstarExemplarSecondTriggeredAbility() { - super(Zone.BATTLEFIELD, new DestroyTargetEffect()); + super(Zone.ALL, new DestroyTargetEffect()); this.addTarget(new TargetNonlandPermanent(0, 1)); this.setTriggerPhrase("When {this} dies or is put into exile while its power is 4 or greater, "); this.setLeavesTheBattlefieldTrigger(true); diff --git a/Mage.Sets/src/mage/cards/t/Takklemaggot.java b/Mage.Sets/src/mage/cards/t/Takklemaggot.java index 45ccdda4756..14eb164f46e 100644 --- a/Mage.Sets/src/mage/cards/t/Takklemaggot.java +++ b/Mage.Sets/src/mage/cards/t/Takklemaggot.java @@ -202,7 +202,7 @@ class TakklemaggotUpkeepAbility extends TriggeredAbilityImpl { private final UUID playerId; TakklemaggotUpkeepAbility(UUID playerId) { - super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player") + super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player") .setTargetPointer(new FixedTarget(playerId)), false); this.playerId = playerId; setTriggerPhrase("At the beginning of that player's upkeep, "); diff --git a/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java b/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java new file mode 100644 index 00000000000..80eaafa54f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaleOfKataraAndToph.java @@ -0,0 +1,110 @@ +package mage.cards.t; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +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.WatcherScope; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaleOfKataraAndToph extends CardImpl { + + public TaleOfKataraAndToph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // Creatures you control have "Whenever this creature becomes tapped for the first time during each of your turns, put a +1/+1 counter on it." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new TaleOfKataraAndTophTriggeredAbility(), + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES + )), new TaleOfKataraAndTophWatcher()); + } + + private TaleOfKataraAndToph(final TaleOfKataraAndToph card) { + super(card); + } + + @Override + public TaleOfKataraAndToph copy() { + return new TaleOfKataraAndToph(this); + } +} + +class TaleOfKataraAndTophTriggeredAbility extends TriggeredAbilityImpl { + + TaleOfKataraAndTophTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter on it")); + setTriggerPhrase("Whenever this creature becomes tapped for the first time during each of your turns, "); + } + + private TaleOfKataraAndTophTriggeredAbility(final TaleOfKataraAndTophTriggeredAbility ability) { + super(ability); + } + + @Override + public TaleOfKataraAndTophTriggeredAbility copy() { + return new TaleOfKataraAndTophTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TAPPED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(getControllerId()) + && event.getTargetId().equals(getSourceId()) + && TaleOfKataraAndTophWatcher.checkEvent(game, this, event); + } +} + +class TaleOfKataraAndTophWatcher extends Watcher { + + private final Map map = new HashMap<>(); + + TaleOfKataraAndTophWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TAPPED) { + map.putIfAbsent(new MageObjectReference(event.getTargetId(), game), event.getId()); + } + } + + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static boolean checkEvent(Game game, Ability source, GameEvent event) { + return Objects.equals( + game.getState() + .getWatcher(TaleOfKataraAndTophWatcher.class) + .map + .get(new MageObjectReference(source.getSourceObject(game), game)), + event.getId() + ); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TaleOfMomo.java b/Mage.Sets/src/mage/cards/t/TaleOfMomo.java new file mode 100644 index 00000000000..b7f19660166 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaleOfMomo.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CreatureLeftThisTurnCondition; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +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.watchers.common.CreatureLeftBattlefieldWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaleOfMomo extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("an Ally creature card"); + + static { + filter.add(SubType.ALLY.getPredicate()); + } + + public TaleOfMomo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + // This spell costs {2} less to cast if a creature left the battlefield under your control this turn. + this.addAbility(new SimpleStaticAbility( + new SpellCostReductionSourceEffect(2, CreatureLeftThisTurnCondition.instance) + ).addHint(CreatureLeftThisTurnCondition.getHint()), new CreatureLeftBattlefieldWatcher()); + + // Search your library and/or graveyard for an Ally creature card, reveal it, and put it into your hand. If you search your library this way, shuffle. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter)); + } + + private TaleOfMomo(final TaleOfMomo card) { + super(card); + } + + @Override + public TaleOfMomo copy() { + return new TaleOfMomo(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TalesOfMasterSeshiro.java b/Mage.Sets/src/mage/cards/t/TalesOfMasterSeshiro.java index 6f85e081486..5f9a0a4d45d 100644 --- a/Mage.Sets/src/mage/cards/t/TalesOfMasterSeshiro.java +++ b/Mage.Sets/src/mage/cards/t/TalesOfMasterSeshiro.java @@ -5,10 +5,10 @@ import mage.abilities.effects.Effects; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; @@ -21,20 +21,22 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TalesOfMasterSeshiro extends CardImpl { +public final class TalesOfMasterSeshiro extends TransformingDoubleFacedCard { public TalesOfMasterSeshiro(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.s.SeshirosLivingLegacy.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{4}{G}", + "Seshiro's Living Legacy", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SNAKE, SubType.WARRIOR}, "G" + ); + // Tales of Master Seshiro // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Put a +1/+1 counter on target creature or Vehicle you control. It gains vigilance until end of turn. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new Effects( new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new GainAbilityTargetEffect(VigilanceAbility.getInstance()) @@ -43,10 +45,18 @@ public final class TalesOfMasterSeshiro extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Seshiro's Living Legacy + this.getRightHalfCard().setPT(5, 5); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); } private TalesOfMasterSeshiro(final TalesOfMasterSeshiro card) { diff --git a/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java b/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java index 6db926dfb59..e6d6683fe6a 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoInquisitiveStudent.java @@ -1,50 +1,87 @@ package mage.cards.t; -import mage.MageInt; -import mage.constants.Pronoun; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.AttacksAllTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DrawNthCardTriggeredAbility; -import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount; +import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.emblems.TamiyoSeasonedScholarEmblem; +import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** * @author Susucr */ -public final class TamiyoInquisitiveStudent extends CardImpl { +public final class TamiyoInquisitiveStudent extends TransformingDoubleFacedCard { + + private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true); public TamiyoInquisitiveStudent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MOONFOLK, SubType.WIZARD}, "{U}", + "Tamiyo, Seasoned Scholar", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.TAMIYO}, "GU"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.MOONFOLK); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(0); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = TamiyoSeasonedScholar.class; + this.getLeftHalfCard().setPT(0, 3); + this.getRightHalfCard().setStartingLoyalty(2); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever Tamiyo, Inquisitive Student attacks, investigate. - this.addAbility(new AttacksTriggeredAbility(new InvestigateEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new InvestigateEffect())); // When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control. - this.addAbility(new TransformAbility()); - this.addAbility(new DrawNthCardTriggeredAbility( + this.getLeftHalfCard().addAbility(new DrawNthCardTriggeredAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE), false, 3 ).setTriggerPhrase("When you draw your third card in a turn, ")); + + // Tamiyo, Seasoned Scholar + + // +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn. + this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( + new UntilYourNextTurnDelayedTriggeredAbility( + new AttacksAllTriggeredAbility( + new BoostTargetEffect(-1, 0, Duration.EndOfTurn) + .setText("it gets -1/-0 until end of turn"), + false, StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PERMANENT, true + ) + ) + ), 2)); + + // -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color. + Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.getRightHalfCard().addAbility(ability); + + // -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size." + ability = new LoyaltyAbility( + new DrawCardSourceControllerEffect(xValue) + .setText("Draw cards equal to half the number of cards in your library, rounded up."), + -7 + ); + ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem())); + this.getRightHalfCard().addAbility(ability); } private TamiyoInquisitiveStudent(final TamiyoInquisitiveStudent card) { @@ -56,3 +93,36 @@ public final class TamiyoInquisitiveStudent extends CardImpl { return new TamiyoInquisitiveStudent(this); } } + +class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect { + + TamiyoSeasonedScholarMinus3Effect() { + super(Outcome.DrawCard); + this.staticText = "Return target instant or sorcery card from your graveyard to your hand. " + + "If it's a green card, add one mana of any color"; + } + + private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) { + super(effect); + } + + @Override + public TamiyoSeasonedScholarMinus3Effect copy() { + return new TamiyoSeasonedScholarMinus3Effect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(source.getFirstTarget()); + if (card == null) { + return false; + } + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(getTargetPointer().copy()); + effect.apply(game, source); + if (card.getColor(game).isGreen()) { + new AddManaOfAnyColorEffect().apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java b/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java deleted file mode 100644 index 22fb297f6d1..00000000000 --- a/Mage.Sets/src/mage/cards/t/TamiyoSeasonedScholar.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.AttacksAllTriggeredAbility; -import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount; -import mage.abilities.dynamicvalue.common.HalfValue; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.mana.AddManaOfAnyColorEffect; -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.command.emblems.TamiyoSeasonedScholarEmblem; -import mage.target.common.TargetCardInYourGraveyard; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TamiyoSeasonedScholar extends CardImpl { - - private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true); - - public TamiyoSeasonedScholar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.TAMIYO); - this.setStartingLoyalty(2); - - this.color.setGreen(true); - this.color.setBlue(true); - this.nightCard = true; - - // +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn. - this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( - new UntilYourNextTurnDelayedTriggeredAbility( - new AttacksAllTriggeredAbility( - new BoostTargetEffect(-1, 0, Duration.EndOfTurn) - .setText("it gets -1/-0 until end of turn"), - false, StaticFilters.FILTER_PERMANENT_CREATURE, - SetTargetPointer.PERMANENT, true - ) - ) - ), 2)); - - // -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color. - Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); - this.addAbility(ability); - - // -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size." - ability = new LoyaltyAbility( - new DrawCardSourceControllerEffect(xValue) - .setText("Draw cards equal to half the number of cards in your library, rounded up."), - -7 - ); - ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem())); - this.addAbility(ability); - } - - private TamiyoSeasonedScholar(final TamiyoSeasonedScholar card) { - super(card); - } - - @Override - public TamiyoSeasonedScholar copy() { - return new TamiyoSeasonedScholar(this); - } -} - -class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect { - - TamiyoSeasonedScholarMinus3Effect() { - super(Outcome.DrawCard); - this.staticText = "Return target instant or sorcery card from your graveyard to your hand. " - + "If it's a green card, add one mana of any color"; - } - - private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) { - super(effect); - } - - @Override - public TamiyoSeasonedScholarMinus3Effect copy() { - return new TamiyoSeasonedScholarMinus3Effect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getFirstTarget()); - if (card == null) { - return false; - } - Effect effect = new ReturnToHandTargetEffect(); - effect.setTargetPointer(getTargetPointer().copy()); - effect.apply(game, source); - if (card.getColor(game).isGreen()) { - new AddManaOfAnyColorEffect().apply(game, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TandemTakedown.java b/Mage.Sets/src/mage/cards/t/TandemTakedown.java index 7620676e8b1..9670e89d38f 100644 --- a/Mage.Sets/src/mage/cards/t/TandemTakedown.java +++ b/Mage.Sets/src/mage/cards/t/TandemTakedown.java @@ -26,7 +26,7 @@ public final class TandemTakedown extends CardImpl { CardType.PLANESWALKER.getPredicate(), CardType.BATTLE.getPredicate() )); - filter.add(new AnotherTargetPredicate(2)); + filter.add(new AnotherTargetPredicate(3)); } public TandemTakedown(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TangleclawWerewolf.java b/Mage.Sets/src/mage/cards/t/TangleclawWerewolf.java index 4777b4073b6..68f64afa8e5 100644 --- a/Mage.Sets/src/mage/cards/t/TangleclawWerewolf.java +++ b/Mage.Sets/src/mage/cards/t/TangleclawWerewolf.java @@ -1,42 +1,52 @@ - package mage.cards.t; -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.common.TransformSourceEffect; import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 LevelX2 */ -public final class TangleclawWerewolf extends CardImpl { +public final class TangleclawWerewolf extends TransformingDoubleFacedCard { public TangleclawWerewolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(2); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{2}{G}{G}", + "Fibrous Entangler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, "" + ); - this.secondSideCardClazz = mage.cards.f.FibrousEntangler.class; + // Tangleclaw Werewolf + this.getLeftHalfCard().setPT(2, 4); // Tangleclaw Werewolf can block an additional creature each combat. - this.addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect(Duration.WhileOnBattlefield, 1))); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect(Duration.WhileOnBattlefield, 1))); // {6}{G}: Transform Tangleclaw Werewolf. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{G}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{6}{G}"))); + + // Fibrous Entangler + this.getRightHalfCard().setPT(4, 6); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Fibrous Entangler must be blocked if able. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); + + // Fibrous Entangler can block an additional creature each combat. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect(Duration.WhileOnBattlefield, 1))); } private TangleclawWerewolf(final TangleclawWerewolf card) { diff --git a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java index da974f65989..b3aea14c7bb 100644 --- a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java +++ b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java @@ -2,21 +2,14 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.watchers.Watcher; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -30,10 +23,10 @@ public final class TapestryOfTheAges extends CardImpl { // {2}, {T}: Draw a card. Activate this ability only if you've cast a noncreature spell this turn. Ability ability = new ActivateIfConditionActivatedAbility( new DrawCardSourceControllerEffect(1), - new GenericManaCost(2), PlayerCastNonCreatureSpellCondition.instance + new GenericManaCost(2), CastNoncreatureSpellThisTurnCondition.instance ); ability.addCost(new TapSourceCost()); - this.addAbility(ability, new PlayerCastNonCreatureSpellWatcher()); + this.addAbility(ability.addHint(CastNoncreatureSpellThisTurnCondition.getHint())); } private TapestryOfTheAges(final TapestryOfTheAges card) { @@ -45,47 +38,3 @@ public final class TapestryOfTheAges extends CardImpl { return new TapestryOfTheAges(this); } } - -enum PlayerCastNonCreatureSpellCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - PlayerCastNonCreatureSpellWatcher watcher = game.getState().getWatcher(PlayerCastNonCreatureSpellWatcher.class); - return watcher != null && watcher.playerDidCastNonCreatureSpellThisTurn(source.getControllerId()); - } - - @Override - public String toString() { - return "you've cast a noncreature spell this turn"; - } -} - -class PlayerCastNonCreatureSpellWatcher extends Watcher { - - private Set playerIds = new HashSet<>(); - - public PlayerCastNonCreatureSpellWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - Spell spell = (Spell) game.getObject(event.getTargetId()); - if (!spell.isCreature(game)) { - playerIds.add(spell.getControllerId()); - } - } - } - - @Override - public void reset() { - super.reset(); - playerIds.clear(); - } - - public boolean playerDidCastNonCreatureSpellThisTurn(UUID playerId) { - return playerIds.contains(playerId); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TarkirDuneshaper.java b/Mage.Sets/src/mage/cards/t/TarkirDuneshaper.java index 3b20c0913f1..1e2b32000df 100644 --- a/Mage.Sets/src/mage/cards/t/TarkirDuneshaper.java +++ b/Mage.Sets/src/mage/cards/t/TarkirDuneshaper.java @@ -1,12 +1,11 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -15,20 +14,26 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TarkirDuneshaper extends CardImpl { +public final class TarkirDuneshaper extends TransformingDoubleFacedCard { public TarkirDuneshaper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DOG, SubType.WARRIOR}, "{W}", + "Burnished Dunestomper", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.DOG, SubType.WARRIOR}, "WG" + ); - this.subtype.add(SubType.DOG); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(1); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.b.BurnishedDunestomper.class; + // Tarkir Duneshaper + this.getLeftHalfCard().setPT(1, 2); // {4}{G/P}: Transform Tarkir Duneshaper. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G/P}"))); + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{G/P}"))); + + // Burnished Dunestomper + this.getRightHalfCard().setPT(4, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); } private TarkirDuneshaper(final TarkirDuneshaper card) { diff --git a/Mage.Sets/src/mage/cards/t/TarriansJournal.java b/Mage.Sets/src/mage/cards/t/TarriansJournal.java index 3649563facd..5040d9877ef 100644 --- a/Mage.Sets/src/mage/cards/t/TarriansJournal.java +++ b/Mage.Sets/src/mage/cards/t/TarriansJournal.java @@ -1,29 +1,49 @@ package mage.cards.t; -import java.util.UUID; +import mage.MageIdentifier; +import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardHandCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.counter.AddCounterEnteringCreatureEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; 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.stack.Spell; +import mage.game.stack.StackObject; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.util.SubTypes; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * * @author jeffwadsworth */ -public class TarriansJournal extends CardImpl { +public class TarriansJournal extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another artifact or creature"); @@ -36,23 +56,33 @@ public class TarriansJournal extends CardImpl { } public TarriansJournal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.t.TheTombOfAclazotz.class; - this.color.setBlack(true); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{B}", + "The Tomb of Aclazotz", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, "" + ); + // Tarrian's Journal // T: Sacrifice another artifact or creature: Draw a card. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {2}, {T}, Discard your hand: Transform Tarrian's Journal. - this.addAbility(new TransformAbility()); Ability transformAbility = new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{2}")); transformAbility.addCost(new TapSourceCost()); transformAbility.addCost(new DiscardHandCost()); - this.addAbility(transformAbility); + this.getLeftHalfCard().addAbility(transformAbility); + + // The Tomb of Aclazotz + // {T}: Add {B}. + this.getRightHalfCard().addAbility(new BlackManaAbility()); + + // You may cast a creature spell from your graveyard this turn. If you do, it enters with a finality counter on it and is a Vampire in addition to its other types. + Ability castSpellAbility = new SimpleActivatedAbility(new TheTombOfAclazotzEffect(), new TapSourceCost()); + castSpellAbility.setIdentifier(MageIdentifier.TheTombOfAclazotzWatcher); + castSpellAbility.addWatcher(new TheTombOfAclazotzWatcher()); + this.getRightHalfCard().addAbility(castSpellAbility); } @@ -66,3 +96,221 @@ public class TarriansJournal extends CardImpl { } } + +class TheTombOfAclazotzEffect extends AsThoughEffectImpl { + + TheTombOfAclazotzEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + staticText = "You may cast a creature spell from your graveyard this turn. If you do, it enters with a finality counter on it and is a Vampire in addition to its other types. (If a creature with a finality counter on it would die, exile it instead.)"; + } + + private TheTombOfAclazotzEffect(final TheTombOfAclazotzEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public TheTombOfAclazotzEffect copy() { + return new TheTombOfAclazotzEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class); + if (watcher != null) { + watcher.addPlayable(source, game); + watcher.addPlayFromAnywhereEffect(this.getId()); + } + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility"); + } + + @Override + public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class); + if (watcher == null + || !watcher.checkPermission(playerId, source, game) + || game.getState().getZone(objectId) != Zone.GRAVEYARD) { + return false; + } + Card card = game.getCard(objectId); + return card != null + && affectedAbility instanceof SpellAbility + && card.getOwnerId().equals(playerId) + && card.isCreature(game); + } +} + +class TheTombOfAclazotzWatcher extends Watcher { + + private final Map> morMap = new HashMap<>(); + private UUID playFromAnywhereEffectId; + + TheTombOfAclazotzWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (GameEvent.EventType.CAST_SPELL.equals(event.getType()) + && event.hasApprovingIdentifier(MageIdentifier.TheTombOfAclazotzWatcher)) { + Spell target = game.getSpell(event.getTargetId()); + Card card = target.getCard(); + if (card != null) { + game.getState().addEffect(new AddCounterEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), + CounterType.FINALITY.createInstance(), Outcome.Neutral), + target.getSpellAbility()); + game.getState().addEffect(new AddSubtypeEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), SubType.VAMPIRE, Outcome.Benefit), card.getSpellAbility()); + // Rule 728.2 we must insure the effect is used (creature is cast successfully) before discarding the play effect + UUID playEffectId = this.getPlayFromAnywhereEffect(); + if (playEffectId != null + && game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().getId().equals(playEffectId)) { + // discard the play effect + game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().discard(); + } + } + } + } + + boolean checkPermission(UUID playerId, Ability source, Game game) { + if (!playerId.equals(source.getControllerId())) { + return false; + } + MageObjectReference mor = new MageObjectReference( + source.getSourceId(), source.getStackMomentSourceZCC(), game + ); + return morMap.computeIfAbsent(mor, m -> new HashMap<>()).getOrDefault(playerId, 0) > 0; + } + + void addPlayable(Ability source, Game game) { + MageObjectReference mor = new MageObjectReference( + source.getSourceId(), source.getStackMomentSourceZCC(), game + ); + morMap.computeIfAbsent(mor, m -> new HashMap<>()) + .compute(source.getControllerId(), CardUtil::setOrIncrementValue); + } + + void addPlayFromAnywhereEffect(UUID uuid) { + playFromAnywhereEffectId = uuid; + } + + UUID getPlayFromAnywhereEffect() { + return playFromAnywhereEffectId; + } + + @Override + public void reset() { + morMap.clear(); + super.reset(); + } + +} + +class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + private final SubType subType; + + AddSubtypeEnteringCreatureEffect(MageObjectReference mor, SubType subType, Outcome outcome) { + super(Duration.WhileOnBattlefield, outcome); + this.mor = mor; + this.subType = subType; + } + + private AddSubtypeEnteringCreatureEffect(final AddSubtypeEnteringCreatureEffect effect) { + super(effect); + this.mor = effect.mor; + this.subType = effect.subType; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL_LATE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject spell = game.getObject(event.getSourceId()); + return spell != null && mor.refersTo(spell, game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Spell target = game.getSpell(event.getSourceId()); + if (target != null) { + AddCardSubTypeEnteringTargetEffect effect = new AddCardSubTypeEnteringTargetEffect(mor, subType, Duration.WhileOnBattlefield); + effect.setTargetPointer(new FixedTarget(target, game)); + game.addEffect(effect, source); + } + return false; + } + + @Override + public AddSubtypeEnteringCreatureEffect copy() { + return new AddSubtypeEnteringCreatureEffect(this); + } +} + +class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl { + + private final SubType addedSubType; + private final MageObjectReference mor; + private Card card; + + AddCardSubTypeEnteringTargetEffect(MageObjectReference mor, SubType addedSubType, Duration duration) { + super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + this.addedSubType = addedSubType; + this.mor = mor; + } + + protected AddCardSubTypeEnteringTargetEffect(final AddCardSubTypeEnteringTargetEffect effect) { + super(effect); + this.addedSubType = effect.addedSubType; + this.mor = effect.mor; + this.card = effect.card; + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getSpell(getTargetPointer().getFirst(game, source)); + MageObject target = game.getObject(getTargetPointer().getFirst(game, source)); + if (spell != null) { + card = spell.getCard(); + } + for (StackObject stackObject : game.getStack()) { + if (stackObject instanceof Spell + && target != null + && target.equals(stackObject) + && mor.refersTo(target, game)) { + setCreatureSubtype(stackObject, addedSubType, game); + setCreatureSubtype(((Spell) stackObject).getCard(), addedSubType, game); + } + } + if (card != null + && game.getPermanent(card.getId()) != null + && game.getState().getZoneChangeCounter(card.getId()) == mor.getZoneChangeCounter() + 1) { // blinking, etc + game.getPermanent(card.getId()).addSubType(game, addedSubType); + } + return true; + } + + private void setCreatureSubtype(MageObject object, SubType subtype, Game game) { + SubTypes subTypes = game.getState().getCreateMageObjectAttribute(object, game).getSubtype(); + if (!subTypes.contains(subtype)) { + subTypes.add(subtype); + } + } + + @Override + public AddCardSubTypeEnteringTargetEffect copy() { + return new AddCardSubTypeEnteringTargetEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TavernRuffian.java b/Mage.Sets/src/mage/cards/t/TavernRuffian.java index 804e7551083..22bc66e2b86 100644 --- a/Mage.Sets/src/mage/cards/t/TavernRuffian.java +++ b/Mage.Sets/src/mage/cards/t/TavernRuffian.java @@ -1,9 +1,9 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -12,21 +12,26 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TavernRuffian extends CardImpl { +public final class TavernRuffian extends TransformingDoubleFacedCard { public TavernRuffian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{3}{R}", + "Tavern Smasher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(5); - - this.secondSideCardClazz = mage.cards.t.TavernSmasher.class; + // Tavern Ruffian + this.getLeftHalfCard().setPT(2, 5); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Tavern Smasher + this.getRightHalfCard().setPT(6, 5); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private TavernRuffian(final TavernRuffian card) { diff --git a/Mage.Sets/src/mage/cards/t/TavernSmasher.java b/Mage.Sets/src/mage/cards/t/TavernSmasher.java deleted file mode 100644 index 23e61cd013e..00000000000 --- a/Mage.Sets/src/mage/cards/t/TavernSmasher.java +++ /dev/null @@ -1,41 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -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 TavernSmasher extends CardImpl { - - public TavernSmasher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - - this.color.setRed(true); - - this.nightCard = true; - - this.power = new MageInt(6); - this.toughness = new MageInt(5); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private TavernSmasher(final TavernSmasher card) { - super(card); - } - - @Override - public TavernSmasher copy() { - return new TavernSmasher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TeachingsOfTheKirin.java b/Mage.Sets/src/mage/cards/t/TeachingsOfTheKirin.java index 7b0d51758cf..7a9802562c4 100644 --- a/Mage.Sets/src/mage/cards/t/TeachingsOfTheKirin.java +++ b/Mage.Sets/src/mage/cards/t/TeachingsOfTheKirin.java @@ -1,54 +1,84 @@ package mage.cards.t; -import java.util.UUID; - +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.game.Game; import mage.game.permanent.token.SpiritToken; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class TeachingsOfTheKirin extends CardImpl { +public final class TeachingsOfTheKirin extends TransformingDoubleFacedCard { + + private static final FilterCard filter = new FilterCard("noncreature card from a graveyard"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } public TeachingsOfTheKirin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.k.KirinTouchedOrochi.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{G}", + "Kirin-Touched Orochi", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SNAKE, SubType.MONK}, "G" + ); + // Teachings of the Kirin // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I - Mill three cards. Create a 1/1 colorless Spirit creature token. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new MillCardsControllerEffect(3), new CreateTokenEffect(new SpiritToken()) ); // II — Put a +1/+1 counter on target creature you control. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TargetControlledCreaturePermanent() ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Kirin-Touched Orochi + this.getRightHalfCard().setPT(1, 1); + + // Whenever Kirin-Touched Orochi attacks, choose one — + // • Exile target creature card from a graveyard. When you do, create a 1/1 colorless Spirit creature token. + Ability ability = new AttacksTriggeredAbility(new KirinTouchedOrochiTokenEffect()); + ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_A_GRAVEYARD)); + + // • Exile target noncreature card from a graveyard. When you do, put a +1/+1 counter on target creature you control. + Mode mode = new Mode(new KirinTouchedOrochiCounterEffect()); + mode.addTarget(new TargetCardInGraveyard(filter)); + ability.addMode(mode); + this.getRightHalfCard().addAbility(ability); } private TeachingsOfTheKirin(final TeachingsOfTheKirin card) { @@ -60,3 +90,70 @@ public final class TeachingsOfTheKirin extends CardImpl { return new TeachingsOfTheKirin(this); } } + +class KirinTouchedOrochiTokenEffect extends OneShotEffect { + + KirinTouchedOrochiTokenEffect() { + super(Outcome.Exile); + this.staticText = "Exile target creature card from a graveyard. When you do, create a 1/1 colorless Spirit creature token"; + } + + private KirinTouchedOrochiTokenEffect(final KirinTouchedOrochiTokenEffect effect) { + super(effect); + } + + @Override + public KirinTouchedOrochiTokenEffect copy() { + return new KirinTouchedOrochiTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + UUID targetId = source.getFirstTarget(); + Card card = game.getCard(targetId); + if (controller == null || card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { + return false; + } + if (!controller.moveCards(card, Zone.EXILED, source, game)) { + return false; + } + ReflexiveTriggeredAbility reflexiveTokenAbility = new ReflexiveTriggeredAbility(new CreateTokenEffect(new SpiritToken()), false); + game.fireReflexiveTriggeredAbility(reflexiveTokenAbility, source); + return true; + } +} + +class KirinTouchedOrochiCounterEffect extends OneShotEffect { + + KirinTouchedOrochiCounterEffect() { + super(Outcome.Exile); + this.staticText = "Exile target noncreature card from a graveyard. When you do, put a +1/+1 counter on target creature you control"; + } + + private KirinTouchedOrochiCounterEffect(final KirinTouchedOrochiCounterEffect effect) { + super(effect); + } + + @Override + public KirinTouchedOrochiCounterEffect copy() { + return new KirinTouchedOrochiCounterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + UUID targetId = source.getFirstTarget(); + Card card = game.getCard(targetId); + if (controller == null || card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { + return false; + } + if (!controller.moveCards(card, Zone.EXILED, source, game)) { + return false; + } + ReflexiveTriggeredAbility reflexiveCounterAbility = new ReflexiveTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); + reflexiveCounterAbility.addTarget(new TargetControlledCreaturePermanent()); + game.fireReflexiveTriggeredAbility(reflexiveCounterAbility, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeamAvatar.java b/Mage.Sets/src/mage/cards/t/TeamAvatar.java new file mode 100644 index 00000000000..016451df906 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeamAvatar.java @@ -0,0 +1,55 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeamAvatar extends CardImpl { + + public TeamAvatar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of creatures you control. + this.addAbility(new AttacksAloneControlledTriggeredAbility( + new BoostTargetEffect(CreaturesYouControlCount.PLURAL, CreaturesYouControlCount.PLURAL) + .setText("it gets +X/+X until end of turn, where X is the number of creatures you control"), + true, false + ).addHint(CreaturesYouControlHint.instance)); + + // {2}{W}, Discard this card: It deals damage equal to the number of creatures you control to target creature. + Ability ability = new SimpleActivatedAbility( + Zone.HAND, + new DamageTargetEffect(CreaturesYouControlCount.PLURAL) + .setText("it deals damage equal to the number of creatures you control to target creature"), + new ManaCostsImpl<>("{2}{W}") + ); + ability.addCost(new DiscardSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private TeamAvatar(final TeamAvatar card) { + super(card); + } + + @Override + public TeamAvatar copy() { + return new TeamAvatar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TectonicSplit.java b/Mage.Sets/src/mage/cards/t/TectonicSplit.java new file mode 100644 index 00000000000..68ad7b29898 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TectonicSplit.java @@ -0,0 +1,109 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.mana.SimpleManaAbility; +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.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.permanent.CanBeSacrificedPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetSacrifice; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TectonicSplit extends CardImpl { + + public TectonicSplit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); + + // As an additional cost to cast this spell, sacrifice half the lands you control, rounded up. + this.getSpellAbility().addCost(new TectonicSplitCost()); + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + + // Lands you control have "{T}: Add three mana of any one color." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new SimpleManaAbility(new AddManaOfAnyColorEffect(3), new TapSourceCost()), + Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS + ))); + } + + private TectonicSplit(final TectonicSplit card) { + super(card); + } + + @Override + public TectonicSplit copy() { + return new TectonicSplit(this); + } +} + +class TectonicSplitCost extends CostImpl { + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(CanBeSacrificedPredicate.instance); + } + + TectonicSplitCost() { + super(); + setText("sacrifice half the lands you control, rounded up"); + } + + private TectonicSplitCost(final TectonicSplitCost cost) { + super(cost); + } + + @Override + public TectonicSplitCost copy() { + return new TectonicSplitCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return 2 * game.getBattlefield().count(filter, controllerId, source, game) + >= game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, controllerId, source, game); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Player player = game.getPlayer(controllerId); + if (player == null) { + paid = false; + return paid; + } + int count = (1 + game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, controllerId, source, game)) / 2; + if (count == 0) { + paid = true; + return paid; + } + TargetSacrifice target = new TargetSacrifice(count, StaticFilters.FILTER_LAND); + player.choose(Outcome.Sacrifice, target, source, game); + for (UUID targetId : target.getTargets()) { + Optional.ofNullable(targetId) + .map(game::getPermanent) + .ifPresent(permanent -> permanent.sacrifice(source, game)); + } + paid = true; + return paid; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java b/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java deleted file mode 100644 index f9874232e46..00000000000 --- a/Mage.Sets/src/mage/cards/t/TecutlanTheSearingRift.java +++ /dev/null @@ -1,92 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.keyword.DiscoverEffect; -import mage.abilities.mana.RedManaAbility; -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.mageobject.PermanentPredicate; -import mage.game.Game; -import mage.game.stack.Spell; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TecutlanTheSearingRift extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("a permanent spell"); - - static { - filter.add(PermanentPredicate.instance); - } - - public TecutlanTheSearingRift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CAVE); - - // (Transforms from Brass's Tunnel-Grinder.) - this.nightCard = true; - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // Whenever you cast a permanent spell using mana produced by Tecutlan, the Searing Rift, discover X, where X is that spell's mana value. - this.addAbility(new CastSpellPaidBySourceTriggeredAbility( - new TecutlanTheSearingRiftEffect(), - filter, true - )); - } - - private TecutlanTheSearingRift(final TecutlanTheSearingRift card) { - super(card); - } - - @Override - public TecutlanTheSearingRift copy() { - return new TecutlanTheSearingRift(this); - } -} - -class TecutlanTheSearingRiftEffect extends OneShotEffect { - - TecutlanTheSearingRiftEffect() { - super(Outcome.Benefit); - staticText = "discover X, where X is that spell's mana value"; - } - - private TecutlanTheSearingRiftEffect(final TecutlanTheSearingRiftEffect effect) { - super(effect); - } - - @Override - public TecutlanTheSearingRiftEffect copy() { - return new TecutlanTheSearingRiftEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - - Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); - int mv = spell == null ? 0 : Math.max(0, spell.getManaValue()); - - DiscoverEffect.doDiscover(controller, mv, game, source); - return true; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TeferiAkosaOfZhalfir.java b/Mage.Sets/src/mage/cards/t/TeferiAkosaOfZhalfir.java deleted file mode 100644 index 738954cfd63..00000000000 --- a/Mage.Sets/src/mage/cards/t/TeferiAkosaOfZhalfir.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.LoyaltyAbility; -import mage.abilities.common.delayed.ReflexiveTriggeredAbility; -import mage.abilities.costs.common.DiscardTargetCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; -import mage.abilities.effects.common.discard.DiscardControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.game.command.emblems.TeferiAkosaOfZhalfirEmblem; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetCardInHand; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TeferiAkosaOfZhalfir extends CardImpl { - - public TeferiAkosaOfZhalfir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.TEFERI); - this.setStartingLoyalty(4); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // +1: Draw two cards. Then discard two cards unless you discard a creature card. - Ability ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 1); - ability.addEffect(new DoIfCostPaid( - null, new DiscardControllerEffect(2), - new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A)) - .setText("discard a creature card instead of discarding two cards") - ).setText("Then discard two cards unless you discard a creature card")); - this.addAbility(ability); - - // -2: You get an emblem with "Knights you control get +1/+0 and have ward {1}." - this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new TeferiAkosaOfZhalfirEmblem()), -2)); - - // -3: Tap any number of untapped creatures you control. When you do, shuffle target nonland permanent an opponent controls with mana value X or less into its owner's library, where X is the number of creatures tapped this way. - this.addAbility(new LoyaltyAbility(new TeferiAkosaOfZhalfirEffect(), -3)); - } - - private TeferiAkosaOfZhalfir(final TeferiAkosaOfZhalfir card) { - super(card); - } - - @Override - public TeferiAkosaOfZhalfir copy() { - return new TeferiAkosaOfZhalfir(this); - } -} - -class TeferiAkosaOfZhalfirEffect extends OneShotEffect { - - TeferiAkosaOfZhalfirEffect() { - super(Outcome.Benefit); - staticText = "tap any number of untapped creatures you control. When you do, " + - "shuffle target nonland permanent an opponent controls with mana value X or less " + - "into its owner's library, where X is the number of creatures tapped this way"; - } - - private TeferiAkosaOfZhalfirEffect(final TeferiAkosaOfZhalfirEffect effect) { - super(effect); - } - - @Override - public TeferiAkosaOfZhalfirEffect copy() { - return new TeferiAkosaOfZhalfirEffect(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, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, true - ); - player.choose(Outcome.Tap, target, source, game); - int count = 0; - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null && permanent.tap(source, game)) { - count++; - } - } - FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls with mana value " + count + " or less"); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, count + 1)); - ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ShuffleIntoLibraryTargetEffect() - .setText("shuffle target nonland permanent an opponent controls with mana value X or less " + - "into its owner's library, where X is the number of creatures tapped this way"), false); - ability.addTarget(new TargetPermanent(filter)); - game.fireReflexiveTriggeredAbility(ability, source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/Temper.java b/Mage.Sets/src/mage/cards/t/Temper.java index 56e84ea56ba..8d70ed167a3 100644 --- a/Mage.Sets/src/mage/cards/t/Temper.java +++ b/Mage.Sets/src/mage/cards/t/Temper.java @@ -3,6 +3,7 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,10 +11,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -44,22 +42,13 @@ public final class Temper extends CardImpl { class TemperPreventDamageTargetEffect extends PreventionEffectImpl { - private int amount; - private final DynamicValue dVal; - private boolean initialized; - public TemperPreventDamageTargetEffect(DynamicValue dVal, Duration duration) { - super(duration); - this.initialized = false; - this.dVal = dVal; + super(duration, 0, false, true, dVal); staticText = "Prevent the next X damage that would be dealt to target creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature"; } private TemperPreventDamageTargetEffect(final TemperPreventDamageTargetEffect effect) { super(effect); - this.amount = effect.amount; - this.dVal = effect.dVal; - this.initialized = effect.initialized; } @Override @@ -69,36 +58,13 @@ class TemperPreventDamageTargetEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - if (!initialized) { - amount = dVal.calculate(game, source, this); - initialized = true; - } - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int prevented = 0; - if (event.getAmount() >= this.amount) { - int damage = amount; - event.setAmount(event.getAmount() - amount); - this.used = true; - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; - } else { - int damage = event.getAmount(); - event.setAmount(0); - amount -= damage; - 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("Temper: Prevented " + prevented + " damage "); - game.informPlayers("Temper: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); - } + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); } + return false; } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java b/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java deleted file mode 100644 index ca7fc5af6cb..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfAclazotz.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.t; - -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.SacrificeCostCreaturesToughness; -import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.mana.BlackManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TempleOfAclazotz extends CardImpl { - - public TempleOfAclazotz(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // {T}: Add {B} - this.addAbility(new BlackManaAbility()); - - // {T}, Sacrifice a creature: You gain life equal to the sacrificed creature's toughness. - Ability ability = new SimpleActivatedAbility(new GainLifeEffect(SacrificeCostCreaturesToughness.instance) - .setText("you gain life equal to the sacrificed creature's toughness"), new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE)); - this.addAbility(ability); - } - - private TempleOfAclazotz(final TempleOfAclazotz card) { - super(card); - } - - @Override - public TempleOfAclazotz copy() { - return new TempleOfAclazotz(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java b/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java deleted file mode 100644 index 0e5544cfd20..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfCivilization.java +++ /dev/null @@ -1,64 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.mana.WhiteManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TimingRule; -import mage.game.Game; -import mage.watchers.common.PlayerAttackedWatcher; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfCivilization extends CardImpl { - - public TempleOfCivilization(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Ojer Taq, Deepest Foundation.) - - // {T}: Add {W}. - this.addAbility(new WhiteManaAbility()); - - // {2}{W}, {T}: Transform Temple of Civilization. Activate only if you attacked with three or more creatures this turn and only as a sorcery. - Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{W}"), TempleOfCivilizationCondition.instance - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability, new PlayerAttackedWatcher()); - } - - private TempleOfCivilization(final TempleOfCivilization card) { - super(card); - } - - @Override - public TempleOfCivilization copy() { - return new TempleOfCivilization(this); - } -} - -enum TempleOfCivilizationCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - PlayerAttackedWatcher watcher = game.getState().getWatcher(PlayerAttackedWatcher.class); - return watcher != null && watcher.getNumberOfAttackersCurrentTurn(source.getControllerId()) >= 3; - } - - @Override - public String toString() { - return "you attacked with three or more creatures this turn"; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java b/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java deleted file mode 100644 index bd991824891..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfCultivation.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.common.PermanentsYouControlHint; -import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.TimingRule; -import mage.filter.common.FilterControlledPermanent; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfCultivation extends CardImpl { - - private static final Condition condition = new PermanentsOnTheBattlefieldCondition( - new FilterControlledPermanent("you control ten or more permanents"), ComparisonType.MORE_THAN, 9 - ); - - public TempleOfCultivation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Ojer Kaslem, Deepest Growth.) - - // {T}: Add {G}. - this.addAbility(new GreenManaAbility()); - - // {2}{G}, {T}: Transform Temple of Cultivation. Activate only if you control ten or more permanents and only as a sorcery. - Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{G}"), condition - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability.addHint(PermanentsYouControlHint.instance)); - } - - private TempleOfCultivation(final TempleOfCultivation card) { - super(card); - } - - @Override - public TempleOfCultivation copy() { - return new TempleOfCultivation(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java b/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java deleted file mode 100644 index 88fa042529e..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; -import mage.abilities.mana.BlueManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.TimingRule; -import mage.counters.CounterType; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfCyclicalTime extends CardImpl { - - private static final Condition condition = new SourceHasCounterCondition(CounterType.TIME, ComparisonType.EQUAL_TO, 0); - - public TempleOfCyclicalTime(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Ojer Pakpatiq, Deepest Epoch.) - - // {T}: Add {U}. Remove a time counter from Temple of Cyclical Time. - Ability ability = new BlueManaAbility(); - ability.addEffect(new RemoveCounterSourceEffect(CounterType.TIME.createInstance())); - this.addAbility(ability); - - // {2}{U}, {T}: Transform Temple of Cyclical Time. Activate only if it has no time counters on it and only as a sorcery. - ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{U}"), condition - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private TempleOfCyclicalTime(final TempleOfCyclicalTime card) { - super(card); - } - - @Override - public TempleOfCyclicalTime copy() { - return new TempleOfCyclicalTime(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfPower.java b/Mage.Sets/src/mage/cards/t/TempleOfPower.java deleted file mode 100644 index c6bb1dc614d..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfPower.java +++ /dev/null @@ -1,156 +0,0 @@ -package mage.cards.t; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.Hint; -import mage.abilities.mana.RedManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.TimingRule; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.command.CommandObject; -import mage.game.events.DamagedEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.stack.StackObject; -import mage.watchers.Watcher; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfPower extends CardImpl { - - public TempleOfPower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Ojer Axonil, Deepest Might.) - - // {T}: Add {R}. - this.addAbility(new RedManaAbility()); - - // {2}{R}, {T}: Transform Temple of Power. Activate only if red sources you controlled dealt 4 or more noncombat damage this turn and only as a sorcery. - Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{R}"), TempleOfPowerCondition.instance - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability.addHint(TempleOfPowerHint.instance), new TempleOfPowerWatcher()); - } - - private TempleOfPower(final TempleOfPower card) { - super(card); - } - - @Override - public TempleOfPower copy() { - return new TempleOfPower(this); - } -} - -enum TempleOfPowerCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - TempleOfPowerWatcher watcher = game.getState().getWatcher(TempleOfPowerWatcher.class); - return watcher != null - && 4 <= watcher.damageForPlayer(source.getControllerId()); - } - - @Override - public String toString() { - return "red sources you controlled dealt 4 or more noncombat damage this turn"; - } -} - -enum TempleOfPowerHint implements Hint { - instance; - - @Override - public String getText(Game game, Ability ability) { - TempleOfPowerWatcher watcher = game.getState().getWatcher(TempleOfPowerWatcher.class); - if (watcher == null) { - return ""; - } - - return "Non-combat damage from red source: " - + watcher.damageForPlayer(ability.getControllerId()); - } - - @Override - public TempleOfPowerHint copy() { - return instance; - } -} - -class TempleOfPowerWatcher extends Watcher { - - // player -> total non combat damage from red source controlled by that player dealt this turn. - private final Map damageMap = new HashMap<>(); - - public TempleOfPowerWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { - DamagedEvent dmgEvent = (DamagedEvent) event; - - // watch only non combat damage events. - if (dmgEvent == null || dmgEvent.isCombatDamage()) { - return; - } - - MageObject sourceObject; - UUID sourceControllerId = null; - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); - if (sourcePermanent != null) { - // source is a permanent. - sourceObject = sourcePermanent; - sourceControllerId = sourcePermanent.getControllerId(); - } else { - sourceObject = game.getSpellOrLKIStack(event.getSourceId()); - if (sourceObject != null) { - // source is a spell. - sourceControllerId = ((StackObject) sourceObject).getControllerId(); - } else { - sourceObject = game.getObject(event.getSourceId()); - if (sourceObject instanceof CommandObject) { - // source is a Command Object. For instance Emblem - sourceControllerId = ((CommandObject) sourceObject).getControllerId(); - } - } - } - - // watch only red sources dealing damage - if (sourceObject == null || sourceControllerId == null || !sourceObject.getColor().isRed()) { - return; - } - - damageMap.compute(sourceControllerId, (k, i) -> (i == null ? 0 : i) + event.getAmount()); - } - } - - @Override - public void reset() { - damageMap.clear(); - super.reset(); - } - - int damageForPlayer(UUID playerId) { - return damageMap.getOrDefault(playerId, 0); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java b/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java deleted file mode 100644 index 0c63338958b..00000000000 --- a/Mage.Sets/src/mage/cards/t/TempleOfTheDead.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.CardsInHandCondition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.hint.ConditionHint; -import mage.abilities.hint.Hint; -import mage.abilities.mana.BlackManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.TargetController; -import mage.constants.TimingRule; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TempleOfTheDead extends CardImpl { - - private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY); - private static final Hint hint = new ConditionHint(condition); - - public TempleOfTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - this.nightCard = true; - - // (Transforms from Aclazotz, Deepest Betrayal.) - - // {T}: Add {B}. - this.addAbility(new BlackManaAbility()); - - // {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery. - Ability ability = new ActivateIfConditionActivatedAbility( - new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition - ).setTiming(TimingRule.SORCERY); - ability.addCost(new TapSourceCost()); - this.addAbility(ability.addHint(hint)); - } - - private TempleOfTheDead(final TempleOfTheDead card) { - super(card); - } - - @Override - public TempleOfTheDead copy() { - return new TempleOfTheDead(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TemporalCleansing.java b/Mage.Sets/src/mage/cards/t/TemporalCleansing.java index 250e304cc9b..32002794171 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalCleansing.java +++ b/Mage.Sets/src/mage/cards/t/TemporalCleansing.java @@ -1,15 +1,10 @@ package mage.cards.t; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.keyword.ConvokeAbility; 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.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -26,7 +21,7 @@ public final class TemporalCleansing extends CardImpl { this.addAbility(new ConvokeAbility()); // The owner of target nonland permanent puts it into their library second from the top or on the bottom. - this.getSpellAbility().addEffect(new TemporalCleansingEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(2, true)); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } @@ -39,39 +34,3 @@ public final class TemporalCleansing extends CardImpl { return new TemporalCleansing(this); } } - -class TemporalCleansingEffect extends OneShotEffect { - - TemporalCleansingEffect() { - super(Outcome.Benefit); - staticText = "the owner of target nonland permanent puts it into their library second from the top or on the bottom"; - } - - private TemporalCleansingEffect(final TemporalCleansingEffect effect) { - super(effect); - } - - @Override - public TemporalCleansingEffect copy() { - return new TemporalCleansingEffect(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; - } - if (player.chooseUse( - outcome, "Put " + permanent.getIdName() + " second from the top or on the bottom?", - null, "Second from top", "Bottom", source, game - )) { - return player.putCardOnTopXOfLibrary(permanent, game, source, 2, true); - } - return player.putCardsOnBottomOfLibrary(permanent, game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TeoSpiritedGlider.java b/Mage.Sets/src/mage/cards/t/TeoSpiritedGlider.java new file mode 100644 index 00000000000..9f54102d33d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeoSpiritedGlider.java @@ -0,0 +1,100 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +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.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeoSpiritedGlider extends CardImpl { + + public TeoSpiritedGlider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PILOT); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever one or more creatures you control with flying attack, draw a card, then discard a card. When you discard a nonland card this way, put a +1/+1 counter on target creature you control. + Ability ability = new AttacksWithCreaturesTriggeredAbility( + new DrawCardSourceControllerEffect(1), + 1, StaticFilters.FILTER_CREATURE_FLYING + ).setTriggerPhrase("Whenever one or more creatures you control with flying attack, "); + ability.addEffect(new TeoSpiritedGliderEffect()); + this.addAbility(ability); + } + + private TeoSpiritedGlider(final TeoSpiritedGlider card) { + super(card); + } + + @Override + public TeoSpiritedGlider copy() { + return new TeoSpiritedGlider(this); + } +} + +class TeoSpiritedGliderEffect extends OneShotEffect { + + TeoSpiritedGliderEffect() { + super(Outcome.Benefit); + staticText = ", then discard a card. When you discard a nonland card this way, " + + "put a +1/+1 counter on target creature you control"; + } + + private TeoSpiritedGliderEffect(final TeoSpiritedGliderEffect effect) { + super(effect); + } + + @Override + public TeoSpiritedGliderEffect copy() { + return new TeoSpiritedGliderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.discardOne(false, false, source, game); + if (card == null) { + return false; + } + if (card.isLand(game)) { + return true; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/Tephraderm.java b/Mage.Sets/src/mage/cards/t/Tephraderm.java index b11e1487ed2..e18f2d35259 100644 --- a/Mage.Sets/src/mage/cards/t/Tephraderm.java +++ b/Mage.Sets/src/mage/cards/t/Tephraderm.java @@ -4,8 +4,6 @@ import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DealsDamageToThisAllTriggeredAbility; import mage.abilities.dynamicvalue.common.SavedDamageValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -57,7 +55,8 @@ public final class Tephraderm extends CardImpl { class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { TephradermSpellDamageTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(0)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH).withTargetDescription("that spell's controller")); + setTriggerPhrase("Whenever a spell deals damage to {this}, "); } private TephradermSpellDamageTriggeredAbility(final TephradermSpellDamageTriggeredAbility ability) { @@ -74,18 +73,12 @@ class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { if (!event.getTargetId().equals(this.getSourceId())) { return false; } - StackObject sourceSpell = game.getStack().getStackObject(event.getSourceId()); 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())); - ((DamageTargetEffect) effect).setAmount(StaticValue.get(event.getAmount())); - } - } + this.getEffects().setTargetPointer(new FixedTarget(sourceSpell.getControllerId())); + this.getEffects().setValue("damage", event.getAmount()); return true; } - return false; } @@ -94,8 +87,4 @@ class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { return new TephradermSpellDamageTriggeredAbility(this); } - @Override - public String getRule() { - return "Whenever a spell deals damage to {this}, {this} deals that much damage to that spell's controller."; - } } diff --git a/Mage.Sets/src/mage/cards/t/TerraMagicalAdept.java b/Mage.Sets/src/mage/cards/t/TerraMagicalAdept.java index 2b3d125cd26..d52e721e859 100644 --- a/Mage.Sets/src/mage/cards/t/TerraMagicalAdept.java +++ b/Mage.Sets/src/mage/cards/t/TerraMagicalAdept.java @@ -1,52 +1,91 @@ package mage.cards.t; -import mage.MageInt; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; 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.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; import mage.abilities.effects.common.MillThenPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledEnchantmentPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class TerraMagicalAdept extends CardImpl { +public final class TerraMagicalAdept extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent("nonlegendary enchantment you control"); + + static { + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } public TerraMagicalAdept(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD, SubType.WARRIOR}, "{1}{R}{G}", + "Esper Terra", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SAGA, SubType.WIZARD}, "RG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.e.EsperTerra.class; + // Terra, Magical Adept + this.getLeftHalfCard().setPT(4, 2); // When Terra enters, mill five cards. Put up to one enchantment milled this this way into your hand. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( 5, StaticFilters.FILTER_CARD_ENCHANTMENT, true ).setText("mill five cards. Put up to one enchantment card milled this way into your hand"))); // Trance -- {4}{R}{G}, {T}: Exile Terra, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{4}{R}{G}") ); ability.addCost(new TapSourceCost()); - this.addAbility(ability.withFlavorWord("Trance")); + this.getLeftHalfCard().addAbility(ability.withFlavorWord("Trance")); + + // Esper Terra + this.getRightHalfCard().setPT(6, 6); + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard(), SagaChapter.CHAPTER_IV); + + // I, II, III -- Create a token that's a copy of target nonlegendary enchantment you control. It gains haste. If it's a Saga, put up to three lore counters on it. Sacrifice it at the beginning of your next end step. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_III, + new EsperTerraEffect(), new TargetPermanent(filter) + ); + + // IV -- Add {W}{W}, {U}{U}, {B}{B}, {R}{R}, and {G}{G}. Exile Esper Terra, then return it to the battlefield. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_IV, + new BasicManaEffect(new Mana( + 2, 2, 2, 2, 2, 0, 0, 0 + )).setText("add {W}{W}, {U}{U}, {B}{B}, {R}{R}, and {G}{G}"), + new ExileSourceAndReturnFaceUpEffect()); + this.getRightHalfCard().addAbility(sagaAbility); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private TerraMagicalAdept(final TerraMagicalAdept card) { @@ -58,3 +97,48 @@ public final class TerraMagicalAdept extends CardImpl { return new TerraMagicalAdept(this); } } + +class EsperTerraEffect extends OneShotEffect { + + EsperTerraEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of target nonlegendary enchantment you control. " + + "It gains haste. If it's a Saga, put up to three lore counters on it. " + + "Sacrifice it at the beginning of your next end step"; + } + + private EsperTerraEffect(final EsperTerraEffect effect) { + super(effect); + } + + @Override + public EsperTerraEffect copy() { + return new EsperTerraEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.setSavedPermanent(permanent); + effect.addAdditionalAbilities(HasteAbility.getInstance()); + effect.apply(game, source); + for (Permanent token : effect.getAddedPermanents()) { + if (!token.hasSubtype(SubType.SAGA, game)) { + continue; + } + Optional.ofNullable(source.getControllerId()) + .map(game::getPlayer) + .map(player -> player.getAmount( + 0, 3, "Choose how many lore counters to put on " + token.getIdName(), source, game + )) + .filter(amount -> amount > 0) + .ifPresent(amount -> token.addCounters(CounterType.LORE.createInstance(amount), source, game)); + } + effect.removeTokensCreatedAt(game, source, false, PhaseStep.END_TURN, TargetController.YOU); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TerrorOfKruinPass.java b/Mage.Sets/src/mage/cards/t/TerrorOfKruinPass.java deleted file mode 100644 index 987091f32de..00000000000 --- a/Mage.Sets/src/mage/cards/t/TerrorOfKruinPass.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.DoubleStrikeAbility; -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.filter.FilterPermanent; - -import java.util.UUID; - -/** - * @author North - */ -public final class TerrorOfKruinPass extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent(SubType.WEREWOLF, "Werewolves"); - - public TerrorOfKruinPass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.color.setRed(true); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.addAbility(DoubleStrikeAbility.getInstance()); - - // Werewolves you control have menace. (They can't be blocked except by two or more creatures.) - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new MenaceAbility(), Duration.WhileOnBattlefield, filter, false - ))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Terror of Kruin Pass. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private TerrorOfKruinPass(final TerrorOfKruinPass card) { - super(card); - } - - @Override - public TerrorOfKruinPass copy() { - return new TerrorOfKruinPass(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TestOfFaith.java b/Mage.Sets/src/mage/cards/t/TestOfFaith.java index 067582d4dba..7412087c1c2 100644 --- a/Mage.Sets/src/mage/cards/t/TestOfFaith.java +++ b/Mage.Sets/src/mage/cards/t/TestOfFaith.java @@ -1,6 +1,7 @@ package mage.cards.t; import mage.abilities.Ability; +import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.PreventionEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -8,10 +9,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -42,16 +40,14 @@ public final class TestOfFaith extends CardImpl { class TestOfFaithPreventDamageTargetEffect extends PreventionEffectImpl { - private int amount = 3; public TestOfFaithPreventDamageTargetEffect(Duration duration) { - super(duration); + super(duration, 3, false); staticText = "Prevent the next 3 damage that would be dealt to target creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature"; } private TestOfFaithPreventDamageTargetEffect(final TestOfFaithPreventDamageTargetEffect effect) { super(effect); - this.amount = effect.amount; } @Override @@ -61,32 +57,13 @@ class TestOfFaithPreventDamageTargetEffect 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; - if (event.getAmount() >= this.amount) { - int damage = amount; - event.setAmount(event.getAmount() - amount); - this.used = true; - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; - } else { - int damage = event.getAmount(); - event.setAmount(0); - amount -= damage; - 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("Test of Faith: Prevented " + prevented + " damage "); - game.informPlayers("Test of Faith: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); - } + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); } + return false; } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TetzinGnomeChampion.java b/Mage.Sets/src/mage/cards/t/TetzinGnomeChampion.java index 1f93a371526..b6d4297b2eb 100644 --- a/Mage.Sets/src/mage/cards/t/TetzinGnomeChampion.java +++ b/Mage.Sets/src/mage/cards/t/TetzinGnomeChampion.java @@ -1,11 +1,16 @@ package mage.cards.t; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.MillThenPutInHandEffect; +import mage.abilities.effects.common.TransformTargetEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -14,6 +19,8 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.card.DoubleFacedCardPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.permanent.token.GnomeToken; +import mage.target.TargetPermanent; import java.util.UUID; @@ -21,43 +28,62 @@ import java.util.UUID; * * @author jeffwadsworth */ -public class TetzinGnomeChampion extends CardImpl { +public class TetzinGnomeChampion extends TransformingDoubleFacedCard { private static final FilterControlledPermanent filter = new FilterControlledPermanent("double-faced artifact"); + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("other target double-faced artifact you control"); static { filter.add(AnotherPredicate.instance); filter.add(Predicates.and( DoubleFacedCardPredicate.instance, - CardType.ARTIFACT.getPredicate() - ) + CardType.ARTIFACT.getPredicate()) + ); + filter2.add(AnotherPredicate.instance); + filter2.add(Predicates.and( + DoubleFacedCardPredicate.instance, + CardType.ARTIFACT.getPredicate()) ); } public TetzinGnomeChampion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}{R}{W}"); - this.supertype.add(SuperType.LEGENDARY); - this.cardType.add(CardType.CREATURE); - this.subtype.add(SubType.GNOME); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GNOME}, "{U}{R}{W}", + "The Golden-Gear Colossus", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GNOME}, "URW" + ); - this.secondSideCardClazz = mage.cards.t.TheGoldenGearColossus.class; - this.color.setBlue(true); - this.color.setRed(true); - this.color.setWhite(true); + // Tetzin, Gnome Champion + this.getLeftHalfCard().setPT(2, 2); // Whenever Tetzin or another double-faced artifact you control enters, mill three cards. You may put an artifact card from among them into your hand. - this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( new MillThenPutInHandEffect(3, StaticFilters.FILTER_CARD_ARTIFACT_AN).withTextOptions("them"), filter, false, true )); // Craft with six artifacts 4 (4, Exile this artifact, Exile the six from among other permanents you control and/or cards from your graveyard: Return this card transformed under its owner's control. Craft only as a sorcery.) - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{4}", "six artifacts", "other artifacts you control and/or" + "artifact cards in your graveyard", 6, 6, CardType.ARTIFACT.getPredicate() )); + + // The Golden-Gear Colossus + this.getRightHalfCard().setPT(6, 6); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Whenever The Golden-Gear Colossus enters the battlefield or attacks, transform up to one other target double-faced artifact you control. Create two 1/1 colorless Gnome artifact creature tokens. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new TransformTargetEffect()); + TargetPermanent target = new TargetPermanent(0, 1, filter2); + ability.addTarget(target); + ability.addEffect(new CreateTokenEffect(new GnomeToken(), 2)); + this.getRightHalfCard().addAbility(ability); + } private TetzinGnomeChampion(final TetzinGnomeChampion card) { diff --git a/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java b/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java new file mode 100644 index 00000000000..21ef23bc7de --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThatsRoughBuddy.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import mage.abilities.condition.common.CreatureLeftThisTurnCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThatsRoughBuddy extends CardImpl { + + public ThatsRoughBuddy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + this.subtype.add(SubType.LESSON); + + // Put a +1/+1 counter on target creature. Put two +1/+1 counters on that creature instead if a creature left the battlefield under your control this turn. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + CreatureLeftThisTurnCondition.instance, "put a +1/+1 counter on target creature. Put two +1/+1 " + + "counters on that creature instead if a creature left the battlefield under your control this turn" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(CreatureLeftThisTurnCondition.getHint()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private ThatsRoughBuddy(final ThatsRoughBuddy card) { + super(card); + } + + @Override + public ThatsRoughBuddy copy() { + return new ThatsRoughBuddy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java b/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java index 9f87ab86bfc..ad31deb3782 100644 --- a/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java +++ b/Mage.Sets/src/mage/cards/t/ThaumaticCompass.java @@ -6,17 +6,24 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.RemoveFromCombatTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.LandsYouControlHint; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -24,28 +31,51 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ThaumaticCompass extends CardImpl { +public final class ThaumaticCompass extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterLandPermanent("you control seven or more lands"), ComparisonType.MORE_THAN, 6, true ); - public ThaumaticCompass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - this.secondSideCardClazz = mage.cards.s.SpiresOfOrazca.class; + private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("attacking creature an opponent controls"); + static { + filter.add(AttackingPredicate.instance); + } + + public ThaumaticCompass(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "Spires of Orazca", + new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + + // Thaumatic Compass // {3}, {T}: Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library. Ability ability = new SimpleActivatedAbility( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of your end step, if you control seven or more lands, transform Thaumatic Compass. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(condition).addHint(LandsYouControlHint.instance)); + + // Spires of Orazca + // {T}: Add {C}. + this.getRightHalfCard().addAbility(new ColorlessManaAbility()); + + // {T}: Untap target attacking creature an opponent controls and remove it from combat. + Ability ability2 = new SimpleActivatedAbility( + new UntapTargetEffect() + .setText("Untap target attacking creature an opponent controls"), + new TapSourceCost() + ); + ability2.addEffect(new RemoveFromCombatTargetEffect().setText("and remove it from combat")); + ability2.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(ability2); } private ThaumaticCompass(final ThaumaticCompass card) { diff --git a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java index cb659de5718..cba576d9d23 100644 --- a/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java +++ b/Mage.Sets/src/mage/cards/t/TheAesirEscapeValhalla.java @@ -83,7 +83,7 @@ class TheAesirEscapeValhallaOneEffect extends OneShotEffect { controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { - UUID exileId = CardUtil.getExileZoneId(game, source, 1); + UUID exileId = CardUtil.getExileZoneId(game, source); MageObject sourceObject = source.getSourceObject(game); String exileName = sourceObject != null ? sourceObject.getName() : ""; controller.moveCardsToExile(card, source, game, false, exileId, exileName); diff --git a/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java b/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java deleted file mode 100644 index e9cd482513d..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheArgentEtchings.java +++ /dev/null @@ -1,118 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DestroyAllEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.keyword.IncubateEffect; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheArgentEtchings extends CardImpl { - - private static final FilterPermanent filter - = new FilterPermanent("other permanents except for artifacts, lands, and Phyrexians"); - - static { - filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); - filter.add(AnotherPredicate.instance); - } - - public TheArgentEtchings(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.SAGA); - this.color.setWhite(true); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Incubate 2 five times, then transform all Incubator tokens you control. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new TheArgentEtchingsEffect()); - - // II -- Creatures you control get +1/+1 and gain double strike until end of turn. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, - new BoostControlledEffect(1, 1, Duration.EndOfTurn) - .setText("creatures you control get +1/+1"), - new GainAbilityControlledEffect( - DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("and gain double strike until end of turn") - ); - - // III -- Destroy all other permanents except for artifacts, lands, and Phyrexians. Exile The Argent Etchings, then return it to the battlefield. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new DestroyAllEffect(filter), - new ExileSourceAndReturnFaceUpEffect() - ); - this.addAbility(sagaAbility); - } - - private TheArgentEtchings(final TheArgentEtchings card) { - super(card); - } - - @Override - public TheArgentEtchings copy() { - return new TheArgentEtchings(this); - } -} - -class TheArgentEtchingsEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.INCUBATOR); - - static { - filter.add(TokenPredicate.TRUE); - } - - TheArgentEtchingsEffect() { - super(Outcome.Benefit); - staticText = "incubate 2 five times, then transform all Incubator tokens you control"; - } - - private TheArgentEtchingsEffect(final TheArgentEtchingsEffect effect) { - super(effect); - } - - @Override - public TheArgentEtchingsEffect copy() { - return new TheArgentEtchingsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - for (int i = 0; i < 5; i++) { - IncubateEffect.doIncubate(2, game, source); - } - for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source, game - )) { - permanent.transform(source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheArtOfTea.java b/Mage.Sets/src/mage/cards/t/TheArtOfTea.java new file mode 100644 index 00000000000..478b09f941a --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheArtOfTea.java @@ -0,0 +1,39 @@ +package mage.cards.t; + +import mage.abilities.effects.common.CreateTokenEffect; +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.game.permanent.token.FoodToken; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheArtOfTea extends CardImpl { + + public TheArtOfTea(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + this.subtype.add(SubType.LESSON); + + // Put a +1/+1 counter on up to one target creature you control. Create a Food token. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new FoodToken())); + } + + private TheArtOfTea(final TheArtOfTea card) { + super(card); + } + + @Override + public TheArtOfTea copy() { + return new TheArtOfTea(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java b/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java index 70f07c591a2..3476a47d6dd 100644 --- a/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java +++ b/Mage.Sets/src/mage/cards/t/TheBalrogDurinsBane.java @@ -9,7 +9,6 @@ import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; -import mage.abilities.hint.common.PermanentsSacrificedThisTurnHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -23,13 +22,12 @@ import mage.watchers.common.PermanentsSacrificedWatcher; import java.util.UUID; /** - * * @author Susucr */ public final class TheBalrogDurinsBane extends CardImpl { private static final FilterCreaturePermanent filterNonLegendary - = new FilterCreaturePermanent("except by legendary creatures"); + = new FilterCreaturePermanent("except by legendary creatures"); static { filterNonLegendary.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); @@ -37,7 +35,7 @@ public final class TheBalrogDurinsBane extends CardImpl { public TheBalrogDurinsBane(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{R}"); - + this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.AVATAR); this.subtype.add(SubType.DEMON); @@ -46,12 +44,12 @@ public final class TheBalrogDurinsBane extends CardImpl { // This spell costs {1} less to cast for each permanent sacrificed this turn. this.addAbility( - new SimpleStaticAbility( - Zone.ALL, - new SpellCostReductionSourceEffect(PermanentsSacrificedThisTurnCount.instance) - .setText("this spell costs {1} less to cast for each permanent sacrificed this turn") - ).addHint(PermanentsSacrificedThisTurnHint.instance).setRuleAtTheTop(true), - new PermanentsSacrificedWatcher() + new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionSourceEffect(PermanentsSacrificedThisTurnCount.ALL) + .setText("this spell costs {1} less to cast for each permanent sacrificed this turn") + ).addHint(PermanentsSacrificedThisTurnCount.ALL.getHint()).setRuleAtTheTop(true), + new PermanentsSacrificedWatcher() ); // Haste @@ -59,7 +57,7 @@ public final class TheBalrogDurinsBane extends CardImpl { // The Balrog, Durin's Bane can't be blocked except by legendary creatures. this.addAbility(new SimpleEvasionAbility((new CantBeBlockedByCreaturesSourceEffect( - filterNonLegendary, Duration.WhileOnBattlefield + filterNonLegendary, Duration.WhileOnBattlefield )))); // When The Balrog dies, destroy target artifact or creature an opponent controls. diff --git a/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java b/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java new file mode 100644 index 00000000000..53c080c6ec7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheBlueSpirit.java @@ -0,0 +1,73 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsPhaseCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheBlueSpirit extends CardImpl { + + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + + public TheBlueSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // You may cast the first creature spell you cast each turn as though it had flash. + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + new CastAsThoughItHadFlashAllEffect( + Duration.WhileOnBattlefield, StaticFilters.FILTER_CARD_CREATURE + ), TheBlueSpiritCondition.instance + ).setText("you may cast the first creature spell you cast each turn as though it had flash"))); + + // Whenever a nontoken creature you control enters during combat, draw a card. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN + ).withTriggerCondition(condition)); + } + + private TheBlueSpirit(final TheBlueSpirit card) { + super(card); + } + + @Override + public TheBlueSpirit copy() { + return new TheBlueSpirit(this); + } +} + +enum TheBlueSpiritCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getWatcher(SpellsCastWatcher.class) + .getSpellsCastThisTurn(source.getControllerId()) + .stream() + .noneMatch(spell -> spell.isCreature(game)); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java b/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java new file mode 100644 index 00000000000..484bf07e95b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheBoulderReadyToRumble.java @@ -0,0 +1,62 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheBoulderReadyToRumble extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("the number of creatures you control with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Creatures you control with power 4 or greater", xValue); + + public TheBoulderReadyToRumble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.PERFORMER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever The Boulder attacks, earthbend X, where X is the number of creatures you control with power 4 or greater. + Ability ability = new AttacksTriggeredAbility(new EarthbendTargetEffect(xValue, true)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability.addHint(hint)); + } + + private TheBoulderReadyToRumble(final TheBoulderReadyToRumble card) { + super(card); + } + + @Override + public TheBoulderReadyToRumble copy() { + return new TheBoulderReadyToRumble(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheBrokenSky.java b/Mage.Sets/src/mage/cards/t/TheBrokenSky.java deleted file mode 100644 index 934cbd712ea..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheBrokenSky.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.LifelinkAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.permanent.token.WhiteBlackSpiritToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheBrokenSky extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature tokens"); - - static { - filter.add(TokenPredicate.TRUE); - } - - public TheBrokenSky(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.color.setBlack(true); - this.nightCard = true; - - // Creature tokens you control get +1/+0 and have lifelink. - Ability ability = new SimpleStaticAbility(new BoostControlledEffect( - 1, 0, Duration.WhileOnBattlefield, filter - )); - ability.addEffect(new GainAbilityControlledEffect( - LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, filter - ).setText("and have lifelink")); - this.addAbility(ability); - - // At the beginning of your end step, create a 1/1 white and black Spirit creature token with flying. - this.addAbility(new BeginningOfEndStepTriggeredAbility( - new CreateTokenEffect(new WhiteBlackSpiritToken()) - )); - } - - private TheBrokenSky(final TheBrokenSky card) { - super(card); - } - - @Override - public TheBrokenSky copy() { - return new TheBrokenSky(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheCaveOfTwoLovers.java b/Mage.Sets/src/mage/cards/t/TheCaveOfTwoLovers.java new file mode 100644 index 00000000000..b6b045f8321 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheCaveOfTwoLovers.java @@ -0,0 +1,70 @@ +package mage.cards.t; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.AllyToken; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheCaveOfTwoLovers extends CardImpl { + + private static final FilterCard filter = new FilterCard("a Mountain or Cave card"); + + static { + filter.add(Predicates.or( + SubType.MOUNTAIN.getPredicate(), + SubType.CAVE.getPredicate() + )); + } + + public TheCaveOfTwoLovers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Create two 1/1 white Ally creature tokens. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, + new CreateTokenEffect(new AllyToken(), 2) + ); + + // II -- Search your library for a Mountain or Cave card, reveal it, put it into your hand, then shuffle. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true + )); + + // III -- Earthbend 3. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new EarthbendTargetEffect(3), new TargetControlledLandPermanent() + ); + this.addAbility(sagaAbility); + } + + private TheCaveOfTwoLovers(final TheCaveOfTwoLovers card) { + super(card); + } + + @Override + public TheCaveOfTwoLovers copy() { + return new TheCaveOfTwoLovers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheComingOfGalactus.java b/Mage.Sets/src/mage/cards/t/TheComingOfGalactus.java new file mode 100644 index 00000000000..c3069cb8c3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheComingOfGalactus.java @@ -0,0 +1,49 @@ +package mage.cards.t; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +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.GalactusToken; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheComingOfGalactus extends CardImpl { + + public TheComingOfGalactus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.) + SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_IV); + + // I -- Destroy up to one target nonland permanent. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new DestroyTargetEffect(), new TargetNonlandPermanent(0, 1)); + + // II, III -- Each opponent loses 2 life. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_III, new LoseLifeOpponentsEffect(2)); + + // IV -- Create Galactus, a legendary 16/16 black Elder Alien creature token with flying, trample, and "Whenever Galactus attacks, destroy target land." + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_IV, new CreateTokenEffect(new GalactusToken())); + this.addAbility(sagaAbility); + } + + private TheComingOfGalactus(final TheComingOfGalactus card) { + super(card); + } + + @Override + public TheComingOfGalactus copy() { + return new TheComingOfGalactus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheCore.java b/Mage.Sets/src/mage/cards/t/TheCore.java deleted file mode 100644 index 07a9cc149d1..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheCore.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.t; - -import mage.Mana; -import mage.abilities.condition.common.DescendCondition; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.mana.DynamicManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class TheCore extends CardImpl { - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_PERMANENT); - - public TheCore(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - // (Transforms from Matzalantli.) - this.nightCard = true; - - // Fathomless descent -- {T}: Add X mana of any one color, where X is the number of permanent cards in your graveyard. - this.addAbility(new DynamicManaAbility( - Mana.AnyMana(1), xValue, new TapSourceCost(), - "Add X mana of any one color, where X is the number of permanent cards in your graveyard.", - true - ).setAbilityWord(AbilityWord.FATHOMLESS_DESCENT).addHint(DescendCondition.getHint())); - } - - private TheCore(final TheCore card) { - super(card); - } - - @Override - public TheCore copy() { - return new TheCore(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java b/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java index 1e89f2a9483..c8997d7e5e2 100644 --- a/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java +++ b/Mage.Sets/src/mage/cards/t/TheCreationOfAvacyn.java @@ -81,7 +81,7 @@ class TheCreationOfAvacynOneEffect extends OneShotEffect { if (card != null) { // exile it face down card.setFaceDown(true, game); - UUID exileId = CardUtil.getExileZoneId(game, source, 1); + UUID exileId = CardUtil.getExileZoneId(game, source); MageObject sourceObject = source.getSourceObject(game); String exileName = sourceObject != null ? sourceObject.getName() : ""; controller.moveCardsToExile(card, source, game, false, exileId, exileName); diff --git a/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java b/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java index baa92ca3fcc..bdaf1d41a72 100644 --- a/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java +++ b/Mage.Sets/src/mage/cards/t/TheDarknessCrystal.java @@ -23,6 +23,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; 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.util.CardUtil; @@ -139,6 +140,7 @@ class TheDarknessCrystalExileEffect extends ReplacementEffectImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.isDiesEvent() && zEvent.getTarget().isCreature(game) + && !(zEvent.getTarget() instanceof PermanentToken) && game.getOpponents(source.getControllerId()).contains(zEvent.getTarget().getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/t/TheDestinedThief.java b/Mage.Sets/src/mage/cards/t/TheDestinedThief.java index 05e610242ec..73c9238334d 100644 --- a/Mage.Sets/src/mage/cards/t/TheDestinedThief.java +++ b/Mage.Sets/src/mage/cards/t/TheDestinedThief.java @@ -72,7 +72,7 @@ class TheDestinedThiefTriggeredAbility extends TriggeredAbilityImpl implements B new DrawDiscardControllerEffect(1, 1), FullPartyCondition.instance, "draw a card, then discard a card. " + "If you have a full party, instead draw three cards" - ), true); + ), false); setTriggerPhrase("Whenever one or more creatures you control deal combat damage to one or more players, "); } diff --git a/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java b/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java index 798e0674802..86e9be938cb 100644 --- a/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java +++ b/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java @@ -1,47 +1,63 @@ package mage.cards.t; import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; 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.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; +import java.util.Objects; import java.util.UUID; /** * @author TheElk801 */ -public final class TheDragonKamiReborn extends CardImpl { +public final class TheDragonKamiReborn extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON); 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; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{G}", + "Dragon-Kami's Egg", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.EGG}, "G" + ); + // The Dragon-Kami Reborn // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // 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, + this.getLeftHalfCard(), 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Dragon-Kami's Egg + this.getRightHalfCard().setPT(0, 1); + + // 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.getRightHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( + new DragonKamisEggEffect(), false, filter + ).setTriggerPhrase("Whenever {this} or a Dragon you control dies, ")); } private TheDragonKamiReborn(final TheDragonKamiReborn card) { @@ -94,3 +110,39 @@ class TheDragonKamiRebornEffect extends OneShotEffect { return true; } } + +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() + .getCardsOwned(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/t/TheDukeRebelSentry.java b/Mage.Sets/src/mage/cards/t/TheDukeRebelSentry.java new file mode 100644 index 00000000000..44e0cde7d50 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheDukeRebelSentry.java @@ -0,0 +1,64 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheDukeRebelSentry extends CardImpl { + + public TheDukeRebelSentry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // The Duke enters with a +1/+1 counter on him. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + "with a +1/+1 counter on him" + )); + + // {T}, Remove a counter from The Duke: Put a +1/+1 counter on another target creature you control. It gains hexproof until end of turn. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new TapSourceCost() + ); + ability.addCost(new RemoveCountersSourceCost(1)); + ability.addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance()) + .setText("It gains hexproof until end of turn")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.addAbility(ability); + } + + private TheDukeRebelSentry(final TheDukeRebelSentry card) { + super(card); + } + + @Override + public TheDukeRebelSentry copy() { + return new TheDukeRebelSentry(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheEarthKing.java b/Mage.Sets/src/mage/cards/t/TheEarthKing.java new file mode 100644 index 00000000000..b3c54da0b4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheEarthKing.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +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.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.token.BearsCompanionBearToken; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheEarthKing extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public TheEarthKing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When The Earth King enters, create a 4/4 green Bear creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BearsCompanionBearToken()))); + + // Whenever one or more creatures you control with power 4 or greater attack, search your library for up to that many basic land cards, put them onto the battlefield tapped, then shuffle. + this.addAbility(new AttacksWithCreaturesTriggeredAbility(new TheEarthKingEffect(), 1, filter) + .setTriggerPhrase("Whenever one or more creatures you control with power 4 or greater attack, ")); + } + + private TheEarthKing(final TheEarthKing card) { + super(card); + } + + @Override + public TheEarthKing copy() { + return new TheEarthKing(this); + } +} + +class TheEarthKingEffect extends OneShotEffect { + + TheEarthKingEffect() { + super(Outcome.Benefit); + staticText = "search your library for up to that many basic land cards, " + + "put them onto the battlefield tapped, then shuffle"; + } + + private TheEarthKingEffect(final TheEarthKingEffect effect) { + super(effect); + } + + @Override + public TheEarthKingEffect copy() { + return new TheEarthKingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = (Integer) getValue(AttacksWithCreaturesTriggeredAbility.VALUEKEY_NUMBER_ATTACKERS); + return new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 0, count, StaticFilters.FILTER_CARD_BASIC_LANDS + ), true).apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheEmperorOfPalamecia.java b/Mage.Sets/src/mage/cards/t/TheEmperorOfPalamecia.java index 734c875717f..ed36bbb4531 100644 --- a/Mage.Sets/src/mage/cards/t/TheEmperorOfPalamecia.java +++ b/Mage.Sets/src/mage/cards/t/TheEmperorOfPalamecia.java @@ -1,55 +1,70 @@ package mage.cards.t; -import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.mana.ConditionalColoredManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.TargetController; import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterSpell; import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; import java.util.UUID; /** * @author TheElk801 */ -public final class TheEmperorOfPalamecia extends CardImpl { +public final class TheEmperorOfPalamecia extends TransformingDoubleFacedCard { - private final ConditionalManaBuilder manaBuilder - = new ConditionalSpellManaBuilder(StaticFilters.FILTER_SPELLS_NON_CREATURE); + private final ConditionalManaBuilder manaBuilder = new ConditionalSpellManaBuilder(new FilterSpell("a noncreature spell")); private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1, 3); - public TheEmperorOfPalamecia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}"); + private static final FilterCard filter = new FilterCard("noncreature, nonland cards in your graveyard"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.t.TheLordMasterOfHell.class; + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + } + + private static final DynamicValue xValue = new CardsInControllerGraveyardCount(filter); + private static final Hint hint = new ValueHint("Noncreature, nonland cards in your graveyard", xValue); + + public TheEmperorOfPalamecia(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WIZARD}, "{U}{R}", + "The Lord Master of Hell", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON, SubType.NOBLE, SubType.WIZARD}, "UR" + ); + + // The Emperor of Palamecia + this.getLeftHalfCard().setPT(2, 2); // {T}: Add {U} or {R}. Spend this mana only to cast a noncreature spell. - this.addAbility(new ConditionalColoredManaAbility(new TapSourceCost(), Mana.BlueMana(1), manaBuilder)); - this.addAbility(new ConditionalColoredManaAbility(new TapSourceCost(), Mana.RedMana(1), manaBuilder)); + this.getLeftHalfCard().addAbility(new ConditionalColoredManaAbility(new TapSourceCost(), Mana.BlueMana(1), manaBuilder)); + this.getLeftHalfCard().addAbility(new ConditionalColoredManaAbility(new TapSourceCost(), Mana.RedMana(1), manaBuilder)); // Whenever you cast a noncreature spell, if at least four mana was spent to cast it, put a +1/+1 counter on The Emperor of Palamecia. Then if it has three or more +1/+1 counters on it, transform it. - this.addAbility(new TransformAbility()); Ability ability = new SpellCastControllerTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_NONCREATURE_SPELL_FOUR_MANA_SPENT, false @@ -58,7 +73,17 @@ public final class TheEmperorOfPalamecia extends CardImpl { new TransformSourceEffect(), condition, "Then if it has three or more +1/+1 counters on it, transform it" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // The Lord Master of Hell + this.getRightHalfCard().setPT(3, 3); + + // Starfall -- Whenever The Lord Master of Hell attacks, it deals X damage to each opponent, where X is the number of noncreature, nonland cards in your graveyard. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DamagePlayersEffect( + xValue, TargetController.OPPONENT + ).setText("it deals X damage to each opponent, where X is " + + "the number of noncreature, nonland cards in your graveyard")) + .withFlavorWord("Starfall").addHint(hint)); } private TheEmperorOfPalamecia(final TheEmperorOfPalamecia card) { diff --git a/Mage.Sets/src/mage/cards/t/TheEnigmaJewel.java b/Mage.Sets/src/mage/cards/t/TheEnigmaJewel.java index 6a515394202..5869e13e86b 100644 --- a/Mage.Sets/src/mage/cards/t/TheEnigmaJewel.java +++ b/Mage.Sets/src/mage/cards/t/TheEnigmaJewel.java @@ -1,43 +1,69 @@ package mage.cards.t; import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.common.ActivateAbilityTriggeredAbility; import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.CopyStackObjectEffect; import mage.abilities.keyword.CraftAbility; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.common.ActivatedAbilityManaBuilder; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterActivatedOrTriggeredAbility; import mage.filter.predicate.Predicate; +import mage.filter.predicate.other.NotManaAbilityPredicate; +import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; import java.util.UUID; /** * @author TheElk801 */ -public final class TheEnigmaJewel extends CardImpl { +public final class TheEnigmaJewel extends TransformingDoubleFacedCard { + + private static final FilterStackObject filter = new FilterActivatedOrTriggeredAbility("an ability that isn't a mana ability"); + + static { + filter.add(NotManaAbilityPredicate.instance); + } public TheEnigmaJewel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.l.LocusOfEnlightenment.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{U}", + "Locus of Enlightenment", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "U" + ); + // The Enigma Jewel // The Enigma Jewel enters the battlefield tapped. - this.addAbility(new EntersBattlefieldTappedAbility()); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add {C}{C}. Spend this mana only to activate abilities. - this.addAbility(new ConditionalColorlessManaAbility(2, new ActivatedAbilityManaBuilder())); + this.getLeftHalfCard().addAbility(new ConditionalColorlessManaAbility(2, new ActivatedAbilityManaBuilder())); // Craft with four or more nonlands with activated abilities {8}{U} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{8}{U}", "four or more nonlands with activated abilities", "other " + "nonland permanents you control with activated abilities and/or nonland cards in your " + "graveyard with activated abilities", 4, Integer.MAX_VALUE, TheEnigmaJewelPredicate.instance )); + + // Locus of Enlightenment + // Locus of Enlightenment has each activated ability of the exiled cards used to craft it. You may activate each of those abilities only once each turn. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new LocusOfEnlightenmentEffect())); + + // Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy. + this.getRightHalfCard().addAbility(new ActivateAbilityTriggeredAbility(new CopyStackObjectEffect("it"), filter, SetTargetPointer.SPELL)); } private TheEnigmaJewel(final TheEnigmaJewel card) { @@ -62,3 +88,46 @@ enum TheEnigmaJewelPredicate implements Predicate { .anyMatch(a -> (a.isActivatedAbility())); } } + +class LocusOfEnlightenmentEffect extends ContinuousEffectImpl { + + LocusOfEnlightenmentEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.Benefit); + staticText = "{this} has each activated ability of the exiled cards " + + "used to craft it. You may activate each of those abilities only once each turn"; + } + + private LocusOfEnlightenmentEffect(final LocusOfEnlightenmentEffect effect) { + super(effect); + } + + @Override + public LocusOfEnlightenmentEffect copy() { + return new LocusOfEnlightenmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId(game, permanent.getMainCard().getId(), + permanent.getMainCard().getZoneChangeCounter(game) - 1)); + if (exileZone == null) { + return false; + } + for (Card card : exileZone.getCards(game)) { + for (Ability ability : card.getAbilities(game)) { + if (ability.isActivatedAbility()) { + ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); + copyAbility.setMaxActivationsPerTurn(1); + permanent.addAbility(copyAbility, source.getSourceId(), game, true); + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheEverflowingWell.java b/Mage.Sets/src/mage/cards/t/TheEverflowingWell.java index 62aecfd6a98..787947c892a 100644 --- a/Mage.Sets/src/mage/cards/t/TheEverflowingWell.java +++ b/Mage.Sets/src/mage/cards/t/TheEverflowingWell.java @@ -1,42 +1,67 @@ package mage.cards.t; import mage.abilities.Ability; +import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DescendCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.BlueManaAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.PermanentPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author jeffwadsworth */ -public class TheEverflowingWell extends CardImpl { +public class TheEverflowingWell extends TransformingDoubleFacedCard { + + private static final FilterSpell filter = new FilterSpell("a permanent spell"); + + static { + filter.add(PermanentPredicate.instance); + } public TheEverflowingWell(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); - this.supertype.add(SuperType.LEGENDARY); - - this.secondSideCardClazz = mage.cards.t.TheMyriadPools.class; - this.color.setBlue(true); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{U}", + "The Myriad Pools", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.LAND}, new SubType[]{}, "" + ); + // The Everflowing Well // When the Everflowing Well enters the battlefield, mill two cards, then draw two cards. Ability entersAbility = new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2)); entersAbility.addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then")); - this.addAbility(entersAbility); + this.getLeftHalfCard().addAbility(entersAbility); // Descend 8 -- At the beginning of your upkeep, if there are eight or more permanent cards in your graveyard, transform The Everflowing Well. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect()) .withInterveningIf(DescendCondition.EIGHT).setAbilityWord(AbilityWord.DESCEND_8).addHint(DescendCondition.getHint())); + + // The Myriad Pools + // {T}: Add {U}. + this.getRightHalfCard().addAbility(new BlueManaAbility()); + + // Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn. + Ability ability = new CastSpellPaidBySourceTriggeredAbility(new TheMyriadPoolsCopyEffect(), filter, false); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_TARGET_PERMANENT)); + this.getRightHalfCard().addAbility(ability); } private TheEverflowingWell(final TheEverflowingWell card) { @@ -49,3 +74,37 @@ public class TheEverflowingWell extends CardImpl { } } + +class TheMyriadPoolsCopyEffect extends OneShotEffect { + + TheMyriadPoolsCopyEffect() { + super(Outcome.Neutral); + this.staticText = "up to one other target permanent you control becomes a copy of that spell until end of turn"; + } + + private TheMyriadPoolsCopyEffect(final TheMyriadPoolsCopyEffect effect) { + super(effect); + } + + @Override + public TheMyriadPoolsCopyEffect copy() { + return new TheMyriadPoolsCopyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetPermanentToCopyTo = game.getPermanent(getTargetPointer().getFirst(game, source)); + Player controller = game.getPlayer(source.getControllerId()); + Object spell = getValue("spellCast"); + if (controller == null || targetPermanentToCopyTo == null || !(spell instanceof Spell)) { + return false; + } + Permanent newBluePrint = new PermanentCard(((Spell) spell).getCard(), source.getControllerId(), game); + newBluePrint.assignNewId(); + CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, targetPermanentToCopyTo.getId()); + Ability newAbility = source.copy(); + copyEffect.init(newAbility, game); + game.addEffect(copyEffect, newAbility); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheFallOfKroog.java b/Mage.Sets/src/mage/cards/t/TheFallOfKroog.java index 2d16a039f9d..c52ca2da726 100644 --- a/Mage.Sets/src/mage/cards/t/TheFallOfKroog.java +++ b/Mage.Sets/src/mage/cards/t/TheFallOfKroog.java @@ -2,8 +2,7 @@ package mage.cards.t; import mage.MageItem; import mage.abilities.Ability; -import mage.abilities.effects.common.DamageAllControlledTargetEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndAllControlledEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -32,12 +31,9 @@ public final class TheFallOfKroog extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect() .setText("choose target opponent. Destroy target land that player controls") .setTargetPointer(new SecondTargetPointer())); - this.getSpellAbility().addEffect(new DamageTargetEffect( - 3, true, "that player" - )); - this.getSpellAbility().addEffect(new DamageAllControlledTargetEffect( - 1, StaticFilters.FILTER_PERMANENT_CREATURE - ).setText("and 1 damage to each creature they control")); + this.getSpellAbility().addEffect(new DamageTargetAndAllControlledEffect( + 3, 1, StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("{this} deals 3 damage to that player and 1 damage to each creature they control")); this.getSpellAbility().addTarget(new TargetOpponent()); this.getSpellAbility().addTarget(new TheFallOfKroogTarget()); } diff --git a/Mage.Sets/src/mage/cards/t/TheFallOfLordKonda.java b/Mage.Sets/src/mage/cards/t/TheFallOfLordKonda.java index 450b8d2312e..9968ca03993 100644 --- a/Mage.Sets/src/mage/cards/t/TheFallOfLordKonda.java +++ b/Mage.Sets/src/mage/cards/t/TheFallOfLordKonda.java @@ -1,12 +1,14 @@ package mage.cards.t; +import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.continuous.GainControlAllOwnedEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.DefenderAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SagaChapter; @@ -22,7 +24,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TheFallOfLordKonda extends CardImpl { +public final class TheFallOfLordKonda extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("creature an opponent controls with mana value 4 or greater"); @@ -32,34 +34,44 @@ public final class TheFallOfLordKonda extends CardImpl { } public TheFallOfLordKonda(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.f.FragmentOfKonda.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{W}", + "Fragment of Konda", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE}, "W" + ); + // The Fall of Lord Konda // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Exile target creature an opponent controls with mana value 4 or greater. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, new ExileTargetEffect(), new TargetPermanent(filter) ); // II — Each player gains control of all permanents they own. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new GainControlAllOwnedEffect(StaticFilters.FILTER_PERMANENTS) ); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, + this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect() ); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Fragment of Konda + this.getRightHalfCard().setPT(1, 3); + + // Defender + this.getRightHalfCard().addAbility(DefenderAbility.getInstance()); + + // When Fragment of Konda dies, draw a card. + this.getRightHalfCard().addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(1))); } private TheFallOfLordKonda(final TheFallOfLordKonda card) { diff --git a/Mage.Sets/src/mage/cards/t/TheFinalDays.java b/Mage.Sets/src/mage/cards/t/TheFinalDays.java index 9aee7221cfb..c6c9824f468 100644 --- a/Mage.Sets/src/mage/cards/t/TheFinalDays.java +++ b/Mage.Sets/src/mage/cards/t/TheFinalDays.java @@ -30,7 +30,7 @@ public final class TheFinalDays extends CardImpl { // Create two tapped 2/2 black Horror creature tokens. If this spell was cast from a graveyard, instead create X of those tokens, where X is the number of creature cards in your graveyard. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new CreateTokenEffect(new Horror3Token(), xValue), new CreateTokenEffect(new Horror3Token(), 2), + new CreateTokenEffect(new Horror3Token(), xValue, true, false), new CreateTokenEffect(new Horror3Token(), 2, true), CastFromGraveyardSourceCondition.instance, "create two tapped 2/2 black Horror creature tokens. " + "If this spell was cast from a graveyard, instead create X of those tokens, " + "where X is the number of creature cards in your graveyard" diff --git a/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java b/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java new file mode 100644 index 00000000000..7c9f6e8df9c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheFireNationDrill.java @@ -0,0 +1,113 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.CompoundAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +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 TheFireNationDrill extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + public TheFireNationDrill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}{B}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(6); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When The Fire Nation Drill enters, you may tap it. When you do, destroy target creature with power 4 or less. + this.addAbility(new EntersBattlefieldTriggeredAbility(new TheFireNationDrillEffect())); + + // {1}: Permanents your opponents control lose hexproof and indestructible until end of turn. + this.addAbility(new SimpleActivatedAbility(new LoseAbilityAllEffect( + new CompoundAbility(HexproofAbility.getInstance(), IndestructibleAbility.getInstance()), Duration.EndOfTurn, filter + ).setText("permanents your opponents control lose hexproof and indestructible until end of turn."), new GenericManaCost(1))); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private TheFireNationDrill(final TheFireNationDrill card) { + super(card); + } + + @Override + public TheFireNationDrill copy() { + return new TheFireNationDrill(this); + } +} + +// custom effect needed as we can't use TapSourceCost with DoWhenCostPaid due to it not ignoring summoning sickness +class TheFireNationDrillEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 5)); + } + + TheFireNationDrillEffect() { + super(Outcome.Benefit); + staticText = "you may tap it. When you do, destroy target creature with power 4 or less"; + } + + private TheFireNationDrillEffect(final TheFireNationDrillEffect effect) { + super(effect); + } + + @Override + public TheFireNationDrillEffect copy() { + return new TheFireNationDrillEffect(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 + || permanent.isTapped() + || !player.chooseUse(Outcome.Tap, "Tap " + permanent.getIdName() + '?', source, game) + || !permanent.tap(source, game)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false); + ability.addTarget(new TargetPermanent(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheGoldenGearColossus.java b/Mage.Sets/src/mage/cards/t/TheGoldenGearColossus.java deleted file mode 100644 index 02c6add9e7a..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheGoldenGearColossus.java +++ /dev/null @@ -1,74 +0,0 @@ -package mage.cards.t; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.TransformTargetEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.card.DoubleFacedCardPredicate; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.permanent.token.GnomeToken; -import mage.target.TargetPermanent; - -/** - * - * @author jeffwadsworth - */ -public class TheGoldenGearColossus extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("other target double-faced artifact you control"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(Predicates.and( - DoubleFacedCardPredicate.instance, - CardType.ARTIFACT.getPredicate() - ) - ); - } - - public TheGoldenGearColossus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, null); - this.supertype.add(SuperType.LEGENDARY); - this.cardType.add(CardType.CREATURE); - this.subtype.add(SubType.GNOME); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - - this.nightCard = true; - - this.color.setBlue(true); - this.color.setRed(true); - this.color.setWhite(true); - - this.addAbility(VigilanceAbility.getInstance()); - this.addAbility(TrampleAbility.getInstance()); - - // Whenever The Golden-Gear Colossus enters the battlefield or attacks, transform up to one other target double-faced artifact you control. Create two 1/1 colorless Gnome artifact creature tokens. - Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new TransformTargetEffect()); - TargetPermanent target = new TargetPermanent(0, 1, filter); - ability.addTarget(target); - ability.addEffect(new CreateTokenEffect(new GnomeToken(), 2)); - this.addAbility(ability); - - } - - private TheGoldenGearColossus(final TheGoldenGearColossus card) { - super(card); - } - - @Override - public TheGoldenGearColossus copy() { - return new TheGoldenGearColossus(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheGrandEvolution.java b/Mage.Sets/src/mage/cards/t/TheGrandEvolution.java deleted file mode 100644 index cfcde708afd..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheGrandEvolution.java +++ /dev/null @@ -1,108 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.FightTargetSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.DistributeCountersEffect; -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.players.Player; -import mage.target.TargetCard; -import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanentAmount; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheGrandEvolution extends CardImpl { - - public TheGrandEvolution(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.SAGA); - this.color.setGreen(true); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- Mill ten cards. Put up to two creature cards from among the milled cards onto the battlefield. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new TheGrandEvolutionEffect()); - - // II -- Distribute seven +1/+1 counters among any number of target creatures you control. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, - new DistributeCountersEffect(), - new TargetCreaturePermanentAmount(7, StaticFilters.FILTER_CONTROLLED_CREATURES) - ); - - // III -- Until end of turn, creatures you control gain "{1}: This creature fights target creature you don't control." Exile The Grand Evolution, then return it to the battlefield. - Ability ability = new SimpleActivatedAbility( - new FightTargetSourceEffect() - .setText("this creature fights target creature you don't control"), - new GenericManaCost(1) - ); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new GainAbilityControlledEffect( - ability, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE - ).setText("Until end of turn, creatures you control gain " + - "\"{1}: This creature fights target creature you don't control.\""), - new ExileSourceAndReturnFaceUpEffect() - ); - this.addAbility(sagaAbility); - } - - private TheGrandEvolution(final TheGrandEvolution card) { - super(card); - } - - @Override - public TheGrandEvolution copy() { - return new TheGrandEvolution(this); - } -} - -class TheGrandEvolutionEffect extends OneShotEffect { - - TheGrandEvolutionEffect() { - super(Outcome.Benefit); - staticText = "mill ten cards. Put up to two creature cards from among the milled cards onto the battlefield"; - } - - private TheGrandEvolutionEffect(final TheGrandEvolutionEffect effect) { - super(effect); - } - - @Override - public TheGrandEvolutionEffect copy() { - return new TheGrandEvolutionEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = player.millCards(10, source, game); - TargetCard target = new TargetCard(0, 2, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE); - target.withNotTarget(true); - player.choose(Outcome.PutCreatureInPlay, cards, target, source, game); - player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheGreatSynthesis.java b/Mage.Sets/src/mage/cards/t/TheGreatSynthesis.java deleted file mode 100644 index 160a80da2a6..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheGreatSynthesis.java +++ /dev/null @@ -1,99 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; -import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.util.CardUtil; - -import java.util.UUID; - -public class TheGreatSynthesis extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Phyrexian creatures"); - - static { - filter.add(Predicates.not(SubType.PHYREXIAN.getPredicate())); - } - - public TheGreatSynthesis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - this.addSubType(SubType.SAGA); - this.color.setBlue(true); - this.nightCard = true; - - //(As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - //I — Draw cards equal to the number of cards in your hand. You have no maximum hand size for as long as you - //control The Great Synthesis. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, - new DrawCardSourceControllerEffect(CardsInControllerHandCount.ANY) - .setText("draw cards equal to the number of cards in your hand"), - new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.WhileOnBattlefield, - MaximumHandSizeControllerEffect.HandSizeModification.SET) - .setText("you have no maximum hand size for as long as you control {this}")); - - //II — Return all non-Phyrexian creatures to their owners' hands. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new ReturnToHandFromBattlefieldAllEffect(filter)); - - //III — You may cast any number of spells from your hand without paying their mana cost. Exile The Great - //Synthesis, then return it to the battlefield (front face up). - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new TheGreatSynthesisCastEffect(), - new ExileSourceAndReturnFaceUpEffect() - ); - - this.addAbility(sagaAbility); - } - - private TheGreatSynthesis(final TheGreatSynthesis card) { - super(card); - } - - @Override - public TheGreatSynthesis copy() { - return new TheGreatSynthesis(this); - } -} - -class TheGreatSynthesisCastEffect extends OneShotEffect { - public TheGreatSynthesisCastEffect() { - super(Outcome.PlayForFree); - this.staticText = "you may cast any number of spells from your hand without paying their mana costs"; - } - - private TheGreatSynthesisCastEffect(final TheGreatSynthesisCastEffect effect) { - super(effect); - } - - @Override - public TheGreatSynthesisCastEffect copy() { - return new TheGreatSynthesisCastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = controller.getHand(); - CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheGreatWork.java b/Mage.Sets/src/mage/cards/t/TheGreatWork.java deleted file mode 100644 index 7db947caf15..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheGreatWork.java +++ /dev/null @@ -1,186 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -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.game.permanent.Permanent; -import mage.game.permanent.token.TreasureToken; -import mage.players.Player; -import mage.target.common.TargetOpponent; -import mage.watchers.common.CastFromGraveyardWatcher; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheGreatWork extends CardImpl { - - public TheGreatWork(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.SAGA); - this.color.setRed(true); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- The Great Work deals 3 damage to target opponent and each creature they control. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, - new TheGreatWorkEffect(), new TargetOpponent() - ); - - // II -- Create three Treasure tokens. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, - new CreateTokenEffect(new TreasureToken(), 3) - ); - - // III -- Until end of turn, you may cast instant and sorcery spells from any graveyard. If a spell cast this way would be put into a graveyard, exile it instead. Exile The Great Work, then return it to the battlefield. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, new TheGreatWorkCastFromGraveyardEffect(), - new TheGreatWorkReplacementEffect(), new ExileSourceAndReturnFaceUpEffect() - ); - this.addAbility(sagaAbility, new CastFromGraveyardWatcher()); - } - - private TheGreatWork(final TheGreatWork card) { - super(card); - } - - @Override - public TheGreatWork copy() { - return new TheGreatWork(this); - } -} - -class TheGreatWorkEffect extends OneShotEffect { - - TheGreatWorkEffect() { - super(Outcome.Benefit); - staticText = "{this} deals 3 damage to target opponent and each creature they control"; - } - - private TheGreatWorkEffect(final TheGreatWorkEffect effect) { - super(effect); - } - - @Override - public TheGreatWorkEffect copy() { - return new TheGreatWorkEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player == null) { - return false; - } - player.damage(3, source, game); - for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game - )) { - permanent.damage(3, source, game); - } - return true; - } -} - -class TheGreatWorkCastFromGraveyardEffect extends AsThoughEffectImpl { - - TheGreatWorkCastFromGraveyardEffect() { - super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "until end of turn, you may cast instant and sorcery spells from any graveyard"; - } - - private TheGreatWorkCastFromGraveyardEffect(final TheGreatWorkCastFromGraveyardEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public TheGreatWorkCastFromGraveyardEffect copy() { - return new TheGreatWorkCastFromGraveyardEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - Card card = game.getCard(objectId); - if (card != null - && affectedControllerId.equals(source.getControllerId()) - && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game) - && Zone.GRAVEYARD.equals(game.getState().getZone(card.getId()))) { - game.getState().setValue("TheGreatWork", card); - return true; - } - return false; - } -} - -class TheGreatWorkReplacementEffect extends ReplacementEffectImpl { - - TheGreatWorkReplacementEffect() { - super(Duration.EndOfTurn, Outcome.Exile); - staticText = "if a spell cast this way would be put into a graveyard, exile it instead"; - } - - private TheGreatWorkReplacementEffect(final TheGreatWorkReplacementEffect effect) { - super(effect); - } - - @Override - public TheGreatWorkReplacementEffect copy() { - return new TheGreatWorkReplacementEffect(this); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Card card = (Card) game.getState().getValue("TheGreatWork"); - if (card != null) { - ((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) { - if (Zone.GRAVEYARD != ((ZoneChangeEvent) event).getToZone()) { - return false; - } - Card card = game.getCard(event.getSourceId()); - if (card == null || (!card.isInstant(game) && !card.isSorcery(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/t/TheGrimCaptain.java b/Mage.Sets/src/mage/cards/t/TheGrimCaptain.java deleted file mode 100644 index 3ec8f196b3f..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheGrimCaptain.java +++ /dev/null @@ -1,112 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SacrificeOpponentsEffect; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.MenaceAbility; -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.game.permanent.Permanent; -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 TheGrimCaptain extends CardImpl { - - public TheGrimCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.SKELETON); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.PIRATE); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.nightCard = true; - this.color.setBlack(true); - - // Menace - this.addAbility(new MenaceAbility(false)); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Lifelink - this.addAbility(LifelinkAbility.getInstance()); - - // Hexproof - this.addAbility(HexproofAbility.getInstance()); - - // Whenever The Grim Captain attacks, each opponent sacrifices a nonland permanent. Then you may put an exiled creature card used to craft The Grim Captain onto the battlefield under your control tapped and attacking. - Ability ability = new AttacksTriggeredAbility(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_NON_LAND)); - ability.addEffect(new TheGrimCaptainEffect()); - this.addAbility(ability); - } - - private TheGrimCaptain(final TheGrimCaptain card) { - super(card); - } - - @Override - public TheGrimCaptain copy() { - return new TheGrimCaptain(this); - } -} - -class TheGrimCaptainEffect extends OneShotEffect { - - TheGrimCaptainEffect() { - super(Outcome.Benefit); - staticText = "Then you may put an exiled creature card used to craft {this} " + - "onto the battlefield under your control tapped and attacking"; - } - - private TheGrimCaptainEffect(final TheGrimCaptainEffect effect) { - super(effect); - } - - @Override - public TheGrimCaptainEffect copy() { - return new TheGrimCaptainEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCard target = new TargetCardInExile( - 0, 1, StaticFilters.FILTER_CARD_CREATURE, - CardUtil.getExileZoneId(game, source, -2) - ); - target.withNotTarget(true); - player.choose(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return false; - } - player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); - Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); - if (permanent == null) { - return false; - } - game.getCombat().addAttackingCreature(card.getId(), game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheKamiWar.java b/Mage.Sets/src/mage/cards/t/TheKamiWar.java index 62364fcf76d..05f5d7da75d 100644 --- a/Mage.Sets/src/mage/cards/t/TheKamiWar.java +++ b/Mage.Sets/src/mage/cards/t/TheKamiWar.java @@ -1,29 +1,39 @@ package mage.cards.t; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; import mage.target.TargetPermanent; +import mage.target.common.TargetCardInGraveyard; import java.util.UUID; /** * @author TheElk801 */ -public final class TheKamiWar extends CardImpl { +public final class TheKamiWar extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls"); @@ -36,23 +46,25 @@ public final class TheKamiWar extends CardImpl { } 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; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{W}{U}{B}{R}{G}", + "O-Kagachi Made Manifest", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.DRAGON, SubType.SPIRIT}, "WUBRG" + ); + // The Kami War // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Exile target nonland permanent an opponent controls. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + this.getLeftHalfCard(), 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, + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new Effects( new ReturnToHandTargetEffect(), new DiscardEachPlayerEffect(TargetController.OPPONENT) @@ -61,10 +73,26 @@ public final class TheKamiWar extends CardImpl { ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // O-Kagachi Made Manifest + this.getRightHalfCard().setPT(6, 6); + + // O-Kagachi Made Manifest is all colors. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new InfoEffect("{this} is all colors"))); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Trample + this.getRightHalfCard().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.getRightHalfCard().addAbility(new AttacksTriggeredAbility( + new OKagachiMadeManifestEffect(), false, null, SetTargetPointer.PLAYER + )); } private TheKamiWar(final TheKamiWar card) { @@ -76,3 +104,57 @@ public final class TheKamiWar extends CardImpl { return new TheKamiWar(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.withNotTarget(true); + player.choose(Outcome.ReturnToHand, controller.getGraveyard(), target, source, 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/t/TheLastAgniKai.java b/Mage.Sets/src/mage/cards/t/TheLastAgniKai.java new file mode 100644 index 00000000000..a35026f1559 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLastAgniKai.java @@ -0,0 +1,92 @@ +package mage.cards.t; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.YouDontLoseManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetpointer.EachTargetPointer; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class TheLastAgniKai extends CardImpl { + + public TheLastAgniKai(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Target creature you control fights target creature an opponent controls. If the creature the opponent controls is dealt excess damage this way, add that much {R}. + this.getSpellAbility().addEffect(new TheLastAgniKaiEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + + // Until end of turn, you don't lose unspent red mana as steps and phases end. + this.getSpellAbility().addEffect(new YouDontLoseManaEffect(Duration.EndOfTurn, ManaType.RED).concatBy("
")); + } + + private TheLastAgniKai(final TheLastAgniKai card) { + super(card); + } + + @Override + public TheLastAgniKai copy() { + return new TheLastAgniKai(this); + } +} + +class TheLastAgniKaiEffect extends OneShotEffect { + + TheLastAgniKaiEffect() { + super(Outcome.Benefit); + staticText = "target creature you control fights target creature an opponent controls. " + + "If the creature the opponent controls is dealt excess damage this way, add that much {R}"; + this.setTargetPointer(new EachTargetPointer()); + } + + private TheLastAgniKaiEffect(final TheLastAgniKaiEffect effect) { + super(effect); + } + + @Override + public TheLastAgniKaiEffect copy() { + return new TheLastAgniKaiEffect(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.size() < 2) { + return false; + } + int excess = permanents.get(0).fightWithExcess(permanents.get(1), source, game, true); + if (excess > 0) { + Optional.ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .ifPresent(player -> player.getManaPool().addMana(Mana.RedMana(excess), game, source)); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfKuruk.java b/Mage.Sets/src/mage/cards/t/TheLegendOfKuruk.java new file mode 100644 index 00000000000..55fb361f9f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfKuruk.java @@ -0,0 +1,73 @@ +package mage.cards.t; + +import mage.abilities.common.SagaAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.ExhaustAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.SpiritWorldToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLegendOfKuruk extends TransformingDoubleFacedCard { + + public TheLegendOfKuruk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{U}{U}", + "Avatar Kuruk", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "U" + ); + + // The Legend of Kuruk + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); + + // I, II -- Scry 2, then draw a card. + sagaAbility.addChapterEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + new Effects( + new ScryEffect(2, false), + new DrawCardSourceControllerEffect(1).concatBy(", then") + ) + ); + + // III -- Exile this Saga, then return it to the battlefield transformed under your control. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Avatar Kuruk + this.getRightHalfCard().setPT(4, 3); + + // Whenever you cast a spell, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures." + this.getRightHalfCard().addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new SpiritWorldToken()), StaticFilters.FILTER_SPELL_A, false + )); + + // Exhaust -- Waterbend {20}: Take an extra turn after this one. + this.getRightHalfCard().addAbility(new ExhaustAbility(new AddExtraTurnControllerEffect(), new WaterbendCost(20))); + } + + private TheLegendOfKuruk(final TheLegendOfKuruk card) { + super(card); + } + + @Override + public TheLegendOfKuruk copy() { + return new TheLegendOfKuruk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java b/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java new file mode 100644 index 00000000000..162268e8b3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfKyoshi.java @@ -0,0 +1,93 @@ +package mage.cards.t; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; +import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLegendOfKyoshi extends TransformingDoubleFacedCard { + + public TheLegendOfKyoshi(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{4}{G}{G}", + "Avatar Kyoshi", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "" + ); + + // The Legend of Kyoshi + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); + + // I -- Draw cards equal to the greatest power among creatures you control. + sagaAbility.addChapterEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, + new DrawCardSourceControllerEffect(GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES) + .setText("draw cards equal to the greatest power among creatures you control") + ); + + // II -- Earthbend X, where X is the number of cards in your hand. That land becomes an Island in addition to its other types. + sagaAbility.addChapterEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new Effects( + new EarthbendTargetEffect(CardsInControllerHandCount.ANY, true) + .setText("earthbend X, where X is the number of cards in your hand"), + new AddCardSubTypeTargetEffect(SubType.ISLAND, Duration.Custom) + .setText("That land becomes an Island in addition to its other types") + ), new TargetControlledLandPermanent() + ); + + // III -- Exile this Saga, then return it to the battlefield transformed under your control. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility.addHint(GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES.getHint())); + + // Avatar Kyoshi + this.getRightHalfCard().setPT(5, 4); + + // Lands you control have trample and hexproof. + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS + )); + ability.addEffect(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS + ).setText("and hexproof")); + this.getRightHalfCard().addAbility(ability); + + // {T}: Add X mana of any one color, where X is the greatest power among creatures you control. + this.getRightHalfCard().addAbility(new DynamicManaAbility( + Mana.AnyMana(1), GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES, + new TapSourceCost(), "add X mana of any one color, " + + "where X is the greatest power among creatures you control", true + ).addHint(GreatestAmongPermanentsValue.POWER_CONTROLLED_CREATURES.getHint())); + } + + private TheLegendOfKyoshi(final TheLegendOfKyoshi card) { + super(card); + } + + @Override + public TheLegendOfKyoshi copy() { + return new TheLegendOfKyoshi(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java b/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java new file mode 100644 index 00000000000..2914dd2741b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfRoku.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.game.permanent.token.DragonFirebendingToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLegendOfRoku extends TransformingDoubleFacedCard { + + public TheLegendOfRoku(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{R}{R}", + "Avatar Roku", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "" + ); + + // The Legend of Roku + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); + + // I -- Exile the top three cards of your library. Until the end of your next turn, you may play those cards. + sagaAbility.addChapterEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, + new ExileTopXMayPlayUntilEffect(3, Duration.UntilEndOfYourNextTurn) + ); + + // II -- Add one mana of any color. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new AddManaOfAnyColorEffect(1)); + + // III -- Exile this Saga, then return it to the battlefield transformed under your control. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Avatar Roku + this.getRightHalfCard().setPT(4, 4); + + // Firebending 4 + this.getRightHalfCard().addAbility(new FirebendingAbility(4)); + + // {8}: Create a 4/4 red Dragon creature token with flying and firebending 4. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new DragonFirebendingToken()), new GenericManaCost(8) + )); + } + + private TheLegendOfRoku(final TheLegendOfRoku card) { + super(card); + } + + @Override + public TheLegendOfRoku copy() { + return new TheLegendOfRoku(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java b/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java new file mode 100644 index 00000000000..ab1dd21f630 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLegendOfYangchen.java @@ -0,0 +1,132 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.CastSecondSpellTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +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.TargetOpponent; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheLegendOfYangchen extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public TheLegendOfYangchen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{W}{W}", + "Avatar Yangchen", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR}, "" + ); + + // The Legend of Yangchen + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); + + // I -- Starting with you, each player chooses up to one permanent with mana value 3 or greater from among permanents your opponents control. Exile those permanents. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new TheLegendOfYangchenEffect()); + + // II -- You may have target opponent draw three cards. If you do, draw three cards. + sagaAbility.addChapterEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new Effects( + new DrawCardTargetEffect(3).setText("have target opponent draw three cards. If you do"), + new DrawCardSourceControllerEffect(3).concatBy(",") + ), new TargetOpponent(), true + ); + + // III -- Exile this Saga, then return it to the battlefield transformed under your control. + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Avatar Yangchen + this.getRightHalfCard().setPT(4, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever you cast your second spell each turn, airbend up to one other target nonland permanent. + Ability ability = new CastSecondSpellTriggeredAbility(new AirbendTargetEffect()); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.getRightHalfCard().addAbility(ability); + } + + private TheLegendOfYangchen(final TheLegendOfYangchen card) { + super(card); + } + + @Override + public TheLegendOfYangchen copy() { + return new TheLegendOfYangchen(this); + } +} + +class TheLegendOfYangchenEffect extends OneShotEffect { + + TheLegendOfYangchenEffect() { + super(Outcome.Benefit); + staticText = "starting with you, each player chooses up to one permanent with mana value 3 or greater " + + "from among permanents your opponents control. Exile those permanents"; + } + + private TheLegendOfYangchenEffect(final TheLegendOfYangchenEffect effect) { + super(effect); + } + + @Override + public TheLegendOfYangchenEffect copy() { + return new TheLegendOfYangchenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent filter = new FilterPermanent(); + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 2)); + filter.add(Predicates.not(new ControllerIdPredicate(source.getControllerId()))); + Set permanents = new HashSet<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + TargetPermanent target = new TargetPermanent(0, 1, filter, true); + player.choose(Outcome.Exile, target, source, game); + permanents.add(game.getPermanent(target.getFirstTarget())); + } + permanents.removeIf(Objects::isNull); + if (permanents.isEmpty()) { + return false; + } + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.moveCards(permanents, Zone.EXILED, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLionTurtle.java b/Mage.Sets/src/mage/cards/t/TheLionTurtle.java new file mode 100644 index 00000000000..487744f2be8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheLionTurtle.java @@ -0,0 +1,60 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.combat.CantAttackBlockUnlessConditionSourceEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.AnyColorManaAbility; +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 TheLionTurtle extends CardImpl { + + public TheLionTurtle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ELDER); + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.TURTLE); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When The Lion-Turtle enters, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + + // The Lion-Turtle can't attack or block unless there are three or more Lesson cards in your graveyard. + this.addAbility(new SimpleStaticAbility(new CantAttackBlockUnlessConditionSourceEffect(LessonsInGraveCondition.THREE)) + .addHint(LessonsInGraveCondition.getHint())); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private TheLionTurtle(final TheLionTurtle card) { + super(card); + } + + @Override + public TheLionTurtle copy() { + return new TheLionTurtle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java b/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java index c883920df4b..241c6b8d50d 100644 --- a/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java +++ b/Mage.Sets/src/mage/cards/t/TheLongReachOfNight.java @@ -1,48 +1,83 @@ package mage.cards.t; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SagaAbility; import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.SacrificeOpponentsUnlessPayEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SagaChapter; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.card.DefendingPlayerOwnsCardPredicate; +import mage.game.Game; +import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 */ -public final class TheLongReachOfNight extends CardImpl { +public final class TheLongReachOfNight extends TransformingDoubleFacedCard { + + private static final FilterCard filter + = new FilterCreatureCard("creature cards in defending player's graveyard"); + + static { + filter.add(DefendingPlayerOwnsCardPredicate.instance); + } + + private static final DynamicValue xValue = new CardsInAllGraveyardsCount(filter); public TheLongReachOfNight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.a.AnimusOfNightsReach.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{3}{B}", + "Animus of Night's Reach", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "B" + ); + // The Long Reach of Night // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Each opponent sacrifices a creature unless they discard a card. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new SacrificeOpponentsUnlessPayEffect( new DiscardCardCost(), StaticFilters.FILTER_PERMANENT_CREATURE ) ); // 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.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect() ); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Animus of Night's Reach + this.getRightHalfCard().setPT(0, 4); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // 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.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + xValue, StaticValue.get(0), Duration.EndOfTurn + ).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 TheLongReachOfNight(final TheLongReachOfNight card) { @@ -54,3 +89,28 @@ public final class TheLongReachOfNight extends CardImpl { return new TheLongReachOfNight(this); } } + +enum AnimusOfNightsReachHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + return "Cards in each opponent's graveyard:
" + + game + .getOpponents(ability.getControllerId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(player -> player + .getName() + + ": " + player + .getGraveyard() + .count(StaticFilters.FILTER_CARD_CREATURE, game)) + .collect(Collectors.joining("
")); + } + + @Override + public AnimusOfNightsReachHint copy() { + return instance; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheLordMasterOfHell.java b/Mage.Sets/src/mage/cards/t/TheLordMasterOfHell.java deleted file mode 100644 index 86f366c3704..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheLordMasterOfHell.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; -import mage.abilities.effects.common.DamagePlayersEffect; -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.SuperType; -import mage.constants.TargetController; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TheLordMasterOfHell extends CardImpl { - - private static final FilterCard filter = new FilterCard("noncreature, nonland cards in your graveyard"); - - static { - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - } - - private static final DynamicValue xValue = new CardsInControllerGraveyardCount(filter); - private static final Hint hint = new ValueHint("Noncreature, nonland cards in your graveyard", xValue); - - public TheLordMasterOfHell(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.nightCard = true; - this.color.setBlue(true); - this.color.setRed(true); - - // Starfall -- Whenever The Lord Master of Hell attacks, it deals X damage to each opponent, where X is the number of noncreature, nonland cards in your graveyard. - this.addAbility(new AttacksTriggeredAbility(new DamagePlayersEffect( - xValue, TargetController.OPPONENT - ).setText("it deals X damage to each opponent, where X is " + - "the number of noncreature, nonland cards in your graveyard")) - .withFlavorWord("Starfall").addHint(hint)); - } - - private TheLordMasterOfHell(final TheLordMasterOfHell card) { - super(card); - } - - @Override - public TheLordMasterOfHell copy() { - return new TheLordMasterOfHell(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheMechanistAerialArtisan.java b/Mage.Sets/src/mage/cards/t/TheMechanistAerialArtisan.java new file mode 100644 index 00000000000..5b55075d372 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheMechanistAerialArtisan.java @@ -0,0 +1,74 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +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.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.ClueArtifactToken; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheMechanistAerialArtisan extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledArtifactPermanent("artifact token you control"); + + static { + filter.add(TokenPredicate.TRUE); + } + + public TheMechanistAerialArtisan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARTIFICER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you cast a noncreature spell, create a Clue token. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new ClueArtifactToken()), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + + // {T}: Until end of turn, target artifact token you control becomes a 3/1 Construct artifact creature with flying. + Ability ability = new SimpleActivatedAbility( + new BecomesCreatureTargetEffect( + new CreatureToken( + 3, 1, "3/1 Construct artifact creature with flying", SubType.CONSTRUCT + ).withAbility(FlyingAbility.getInstance()), false, false, Duration.EndOfTurn + ).withDurationRuleAtStart(true), new TapSourceCost() + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private TheMechanistAerialArtisan(final TheMechanistAerialArtisan card) { + super(card); + } + + @Override + public TheMechanistAerialArtisan copy() { + return new TheMechanistAerialArtisan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheModernAge.java b/Mage.Sets/src/mage/cards/t/TheModernAge.java index 8377efec220..191e2cd3e21 100644 --- a/Mage.Sets/src/mage/cards/t/TheModernAge.java +++ b/Mage.Sets/src/mage/cards/t/TheModernAge.java @@ -3,9 +3,9 @@ package mage.cards.t; import mage.abilities.common.SagaAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SagaChapter; import mage.constants.SubType; @@ -15,28 +15,35 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TheModernAge extends CardImpl { +public final class TheModernAge extends TransformingDoubleFacedCard { public TheModernAge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.v.VectorGlider.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{U}", + "Vector Glider", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U" + ); + // The Modern Age // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Draw a card, then discard a card. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new DrawDiscardControllerEffect(1, 1) ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Vector Glider + this.getRightHalfCard().setPT(2, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private TheModernAge(final TheModernAge card) { diff --git a/Mage.Sets/src/mage/cards/t/TheMyriadPools.java b/Mage.Sets/src/mage/cards/t/TheMyriadPools.java deleted file mode 100644 index bcde9f4288f..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheMyriadPools.java +++ /dev/null @@ -1,95 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CopyEffect; -import mage.abilities.mana.BlueManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.filter.FilterSpell; -import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.PermanentPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentCard; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author jeffwadsworth - */ -public class TheMyriadPools extends CardImpl { - - private static final FilterSpell filter = new FilterSpell("a permanent spell"); - - static { - filter.add(PermanentPredicate.instance); - } - - public TheMyriadPools(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, null); - this.supertype.add(SuperType.LEGENDARY); - - // this is the second face of The Everflowing Well - this.nightCard = true; - - // {T}: Add {U}. - this.addAbility(new BlueManaAbility()); - - // Whenever you cast a permanent spell using mana produced by The Myriad Pools, up to one other target permanent you control becomes a copy of that spell until end of turn. - Ability ability = new CastSpellPaidBySourceTriggeredAbility(new TheMyriadPoolsCopyEffect(), filter, false); - ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_TARGET_PERMANENT)); - this.addAbility(ability); - } - - private TheMyriadPools(final TheMyriadPools card) { - super(card); - } - - @Override - public TheMyriadPools copy() { - return new TheMyriadPools(this); - } -} - -class TheMyriadPoolsCopyEffect extends OneShotEffect { - - TheMyriadPoolsCopyEffect() { - super(Outcome.Neutral); - this.staticText = "up to one other target permanent you control becomes a copy of that spell until end of turn"; - } - - private TheMyriadPoolsCopyEffect(final TheMyriadPoolsCopyEffect effect) { - super(effect); - } - - @Override - public TheMyriadPoolsCopyEffect copy() { - return new TheMyriadPoolsCopyEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent targetPermanentToCopyTo = game.getPermanent(getTargetPointer().getFirst(game, source)); - Player controller = game.getPlayer(source.getControllerId()); - Object spell = getValue("spellCast"); - if (controller == null || targetPermanentToCopyTo == null || !(spell instanceof Spell)) { - return false; - } - Permanent newBluePrint = new PermanentCard(((Spell)spell).getCard(), source.getControllerId(), game); - newBluePrint.assignNewId(); - CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, targetPermanentToCopyTo.getId()); - Ability newAbility = source.copy(); - copyEffect.init(newAbility, game); - game.addEffect(copyEffect, newAbility); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheRestorationOfEiganjo.java b/Mage.Sets/src/mage/cards/t/TheRestorationOfEiganjo.java index 3de02b60f26..645601c3a08 100644 --- a/Mage.Sets/src/mage/cards/t/TheRestorationOfEiganjo.java +++ b/Mage.Sets/src/mage/cards/t/TheRestorationOfEiganjo.java @@ -1,15 +1,17 @@ package mage.cards.t; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.common.SagaAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SagaChapter; @@ -18,6 +20,7 @@ import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.permanent.token.SpiritToken; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; @@ -26,7 +29,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TheRestorationOfEiganjo extends CardImpl { +public final class TheRestorationOfEiganjo extends TransformingDoubleFacedCard { private static final FilterCard filter2 = new FilterPermanentCard("permanent card with mana value 2 or less from your graveyard"); @@ -36,17 +39,19 @@ public final class TheRestorationOfEiganjo extends CardImpl { } public TheRestorationOfEiganjo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.a.ArchitectOfRestoration.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{2}{W}", + "Architect of Restoration", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.FOX, SubType.MONK}, "W" + ); + // The Restoration of Eiganjo // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect( new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true ) ); @@ -57,16 +62,24 @@ public final class TheRestorationOfEiganjo extends CardImpl { ); ability.addTarget(new TargetCardInYourGraveyard(filter2)); sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, new DoWhenCostPaid( + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new DoWhenCostPaid( ability, new DiscardCardCost(), "Discard a card?" ) ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Architect of Restoration + this.getRightHalfCard().setPT(3, 4); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Whenever Architect of Restoration attacks or blocks, create a 1/1 colorless Spirit creature token. + this.getRightHalfCard().addAbility(new AttacksOrBlocksTriggeredAbility(new CreateTokenEffect(new SpiritToken()), false)); } private TheRestorationOfEiganjo(final TheRestorationOfEiganjo card) { diff --git a/Mage.Sets/src/mage/cards/t/TheRiseOfSozin.java b/Mage.Sets/src/mage/cards/t/TheRiseOfSozin.java index 78a8b2bd579..3383f91df6a 100644 --- a/Mage.Sets/src/mage/cards/t/TheRiseOfSozin.java +++ b/Mage.Sets/src/mage/cards/t/TheRiseOfSozin.java @@ -1,55 +1,83 @@ package mage.cards.t; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SagaChapter; -import mage.constants.SubType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.card.OwnerIdPredicate; import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** * @author TheElk801 */ -public final class TheRiseOfSozin extends CardImpl { +public final class TheRiseOfSozin extends TransformingDoubleFacedCard { public TheRiseOfSozin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{B}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.f.FireLordSozin.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{4}{B}{B}", + "Fire Lord Sozin", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE}, "B" + ); + // The Rise of Sozin // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I -- Destroy all creatures. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES) + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES) ); // II -- Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. Then that player shuffles. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new Effects( new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), new TheRiseOfSozinEffect() ), new TargetOpponent() ); // 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); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Fire Lord Sozin + this.getRightHalfCard().setPT(5, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Firebending 3 + this.getRightHalfCard().addAbility(new FirebendingAbility(3)); + + // Whenever Fire Lord Sozin deals combat damage to a player, you may pay {X}. When you do, put any number of target creature cards with total mana value X or less from that player's graveyard onto the battlefield under your control. + this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new FireLordSozinEffect())); } private TheRiseOfSozin(final TheRiseOfSozin card) { @@ -83,3 +111,94 @@ class TheRiseOfSozinEffect extends SearchTargetGraveyardHandLibraryForCardNameAn return applySearchAndExile(game, source, chosenCardName, getTargetPointer().getFirst(game, source)); } } + +class FireLordSozinEffect extends OneShotEffect { + + FireLordSozinEffect() { + super(Outcome.Benefit); + staticText = "you may pay {X}. When you do, put any number of target creature cards with " + + "total mana value X or less from that player's graveyard onto the battlefield under your control"; + } + + private FireLordSozinEffect(final FireLordSozinEffect effect) { + super(effect); + } + + @Override + public FireLordSozinEffect copy() { + return new FireLordSozinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + if (!controller.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) { + return false; + } + int xValue = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source, true); + ManaCosts cost = new ManaCostsImpl<>("{X}"); + cost.add(new GenericManaCost(xValue)); + if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); + ability.addTarget(new FireLordSozinTarget((UUID) getValue("damagedPlayer"), xValue)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} + +class FireLordSozinTarget extends TargetCardInGraveyard { + + private final int xValue; + + private static final FilterCard makeFilter(UUID ownerId, int xValue) { + FilterCard filter = new FilterCreatureCard("creature cards with total mana value " + xValue + " or less from that player's graveyard"); + filter.add(new OwnerIdPredicate(ownerId)); + return filter; + } + + FireLordSozinTarget(UUID ownerId, int xValue) { + super(0, Integer.MAX_VALUE, makeFilter(ownerId, xValue), false); + this.xValue = xValue; + } + + private FireLordSozinTarget(final FireLordSozinTarget target) { + super(target); + this.xValue = target.xValue; + } + + @Override + public FireLordSozinTarget copy() { + return new FireLordSozinTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + return super.canTarget(playerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit(this.getTargets(), id, MageObject::getManaValue, xValue, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit( + this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, xValue, game + ); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheSentryGoldenGuardian.java b/Mage.Sets/src/mage/cards/t/TheSentryGoldenGuardian.java new file mode 100644 index 00000000000..b75edce7f1b --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSentryGoldenGuardian.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.TheVoidToken; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheSentryGoldenGuardian extends CardImpl { + + public TheSentryGoldenGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Indestructible + this.addAbility(IndestructibleAbility.getInstance()); + + // When The Sentry enters, target opponent creates The Void, a legendary 5/5 black Horror Villain creature token with flying, indestructible, and "The Void attacks each combat if able." + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenTargetEffect(new TheVoidToken())); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private TheSentryGoldenGuardian(final TheSentryGoldenGuardian card) { + super(card); + } + + @Override + public TheSentryGoldenGuardian copy() { + return new TheSentryGoldenGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheShatteredStatesEra.java b/Mage.Sets/src/mage/cards/t/TheShatteredStatesEra.java index 69b38aa04b7..4b3ee17b6d5 100644 --- a/Mage.Sets/src/mage/cards/t/TheShatteredStatesEra.java +++ b/Mage.Sets/src/mage/cards/t/TheShatteredStatesEra.java @@ -8,9 +8,9 @@ import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SagaChapter; @@ -22,20 +22,22 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TheShatteredStatesEra extends CardImpl { +public final class TheShatteredStatesEra extends TransformingDoubleFacedCard { public TheShatteredStatesEra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.n.NamelessConqueror.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{4}{R}", + "Nameless Conqueror", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SAMURAI}, "R" + ); + // The Shattered States Era // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I — Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, new Effects( new GainControlTargetEffect(Duration.EndOfTurn), new UntapTargetEffect().setText("Untap it."), @@ -47,19 +49,27 @@ public final class TheShatteredStatesEra extends CardImpl { // II — Creatures you control get +1/+0 until end of turn. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, new BoostControlledEffect( + this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new BoostControlledEffect( 1, 0, Duration.EndOfTurn ) ); // III — Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, + this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect() ); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Nameless Conqueror + this.getRightHalfCard().setPT(3, 3); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); } private TheShatteredStatesEra(final TheShatteredStatesEra card) { diff --git a/Mage.Sets/src/mage/cards/t/TheShire.java b/Mage.Sets/src/mage/cards/t/TheShire.java index 1bfbc46d91b..e6744fbc6e1 100644 --- a/Mage.Sets/src/mage/cards/t/TheShire.java +++ b/Mage.Sets/src/mage/cards/t/TheShire.java @@ -3,7 +3,7 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedUnlessAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.YouControlPermanentCondition; +import mage.abilities.condition.common.YouControlALegendaryCreatureCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -13,9 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.FoodToken; import mage.target.common.TargetControlledPermanent; @@ -26,21 +24,14 @@ import java.util.UUID; */ public final class TheShire extends CardImpl { - private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a legendary creature"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - private static final YouControlPermanentCondition condition = new YouControlPermanentCondition(filter); - public TheShire(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.supertype.add(SuperType.LEGENDARY); // The Shire enters the battlefield tapped unless you control a legendary creature. - this.addAbility(new EntersBattlefieldTappedUnlessAbility(condition).addHint(condition.getHint())); + this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlALegendaryCreatureCondition.instance) + .addHint(YouControlALegendaryCreatureCondition.getHint())); // {T}: Add {G}. this.addAbility(new GreenManaAbility()); diff --git a/Mage.Sets/src/mage/cards/t/TheSpiritOasis.java b/Mage.Sets/src/mage/cards/t/TheSpiritOasis.java new file mode 100644 index 00000000000..555db17f626 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSpiritOasis.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.ShrinesYouControlCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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 TheSpiritOasis extends CardImpl { + + public TheSpiritOasis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // When The Spirit Oasis enters, draw a card for each Shrine you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(ShrinesYouControlCount.FOR_EACH))); + + // Whenever another Shrine you control enters, draw a card. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_ANOTHER_CONTROLLED_SHRINE)); + } + + private TheSpiritOasis(final TheSpiritOasis card) { + super(card); + } + + @Override + public TheSpiritOasis copy() { + return new TheSpiritOasis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheThing.java b/Mage.Sets/src/mage/cards/t/TheThing.java new file mode 100644 index 00000000000..456312ec728 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheThing.java @@ -0,0 +1,106 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.common.CastNoncreatureSpellThisTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; +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.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class TheThing extends CardImpl { + + public TheThing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.HERO); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // At the beginning of combat on your turn, if you've cast a noncreature spell this turn, put four +1/+1 counters on The Thing. + this.addAbility(new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4))) + .withInterveningIf(CastNoncreatureSpellThisTurnCondition.instance) + .addHint(CastNoncreatureSpellThisTurnCondition.getHint())); + + // Whenever The Thing attacks, you may pay {R}{G}{W}{U}. When you do, double the number of each kind of counter on any number of target permanents you control. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new TheThingEffect(), false); + ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_PERMANENTS)); + this.addAbility(new AttacksTriggeredAbility(new DoWhenCostPaid( + ability, new ManaCostsImpl<>("{R}{G}{W}{U}"), "Pay {R}{G}{W}{U}?" + ))); + } + + private TheThing(final TheThing card) { + super(card); + } + + @Override + public TheThing copy() { + return new TheThing(this); + } +} + +class TheThingEffect extends OneShotEffect { + + TheThingEffect() { + super(Outcome.Benefit); + staticText = "double the number of each kind of counter on any number of target permanents you control"; + } + + private TheThingEffect(final TheThingEffect effect) { + super(effect); + } + + @Override + public TheThingEffect copy() { + return new TheThingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + continue; + } + Set counters = permanent + .getCounters(game) + .values() + .stream() + .map(Counter::copy) + .collect(Collectors.toSet()); + for (Counter counter : counters) { + permanent.addCounters(counter, source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheTombOfAclazotz.java b/Mage.Sets/src/mage/cards/t/TheTombOfAclazotz.java deleted file mode 100644 index 18e338ca97f..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheTombOfAclazotz.java +++ /dev/null @@ -1,283 +0,0 @@ -package mage.cards.t; - -import mage.MageIdentifier; -import mage.MageObject; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.counter.AddCounterEnteringCreatureEffect; -import mage.abilities.mana.BlackManaAbility; -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.game.events.GameEvent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; -import mage.util.SubTypes; -import mage.watchers.Watcher; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * @author jeffwadsworth - */ -public class TheTombOfAclazotz extends CardImpl { - - public TheTombOfAclazotz(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.CAVE); - - // this is the second face of Tarrian's Journal - this.nightCard = true; - - // {T}: Add {B}. - this.addAbility(new BlackManaAbility()); - - // You may cast a creature spell from your graveyard this turn. If you do, it enters with a finality counter on it and is a Vampire in addition to its other types. - Ability castSpellAbility = new SimpleActivatedAbility(new TheTombOfAclazotzEffect(), new TapSourceCost()); - castSpellAbility.setIdentifier(MageIdentifier.TheTombOfAclazotzWatcher); - castSpellAbility.addWatcher(new TheTombOfAclazotzWatcher()); - this.addAbility(castSpellAbility); - - } - - private TheTombOfAclazotz(final TheTombOfAclazotz card) { - super(card); - } - - @Override - public TheTombOfAclazotz copy() { - return new TheTombOfAclazotz(this); - } -} - -class TheTombOfAclazotzEffect extends AsThoughEffectImpl { - - TheTombOfAclazotzEffect() { - super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may cast a creature spell from your graveyard this turn. If you do, it enters with a finality counter on it and is a Vampire in addition to its other types. (If a creature with a finality counter on it would die, exile it instead.)"; - } - - private TheTombOfAclazotzEffect(final TheTombOfAclazotzEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public TheTombOfAclazotzEffect copy() { - return new TheTombOfAclazotzEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class); - if (watcher != null) { - watcher.addPlayable(source, game); - watcher.addPlayFromAnywhereEffect(this.getId()); - } - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility"); - } - - @Override - public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { - TheTombOfAclazotzWatcher watcher = game.getState().getWatcher(TheTombOfAclazotzWatcher.class); - if (watcher == null - || !watcher.checkPermission(playerId, source, game) - || game.getState().getZone(objectId) != Zone.GRAVEYARD) { - return false; - } - Card card = game.getCard(objectId); - return card != null - && affectedAbility instanceof SpellAbility - && card.getOwnerId().equals(playerId) - && card.isCreature(game); - } -} - -class TheTombOfAclazotzWatcher extends Watcher { - - private final Map> morMap = new HashMap<>(); - private UUID playFromAnywhereEffectId; - - TheTombOfAclazotzWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (GameEvent.EventType.CAST_SPELL.equals(event.getType()) - && event.hasApprovingIdentifier(MageIdentifier.TheTombOfAclazotzWatcher)) { - Spell target = game.getSpell(event.getTargetId()); - Card card = target.getCard(); - if (card != null) { - game.getState().addEffect(new AddCounterEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), - CounterType.FINALITY.createInstance(), Outcome.Neutral), - target.getSpellAbility()); - game.getState().addEffect(new AddSubtypeEnteringCreatureEffect(new MageObjectReference(target.getCard(), game), SubType.VAMPIRE, Outcome.Benefit), card.getSpellAbility()); - // Rule 728.2 we must insure the effect is used (creature is cast successfully) before discarding the play effect - UUID playEffectId = this.getPlayFromAnywhereEffect(); - if (playEffectId != null - && game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().getId().equals(playEffectId)) { - // discard the play effect - game.getContinuousEffects().getApplicableAsThoughEffects(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, game).listIterator().next().discard(); - } - } - } - } - - boolean checkPermission(UUID playerId, Ability source, Game game) { - if (!playerId.equals(source.getControllerId())) { - return false; - } - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getStackMomentSourceZCC(), game - ); - return morMap.computeIfAbsent(mor, m -> new HashMap<>()).getOrDefault(playerId, 0) > 0; - } - - void addPlayable(Ability source, Game game) { - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getStackMomentSourceZCC(), game - ); - morMap.computeIfAbsent(mor, m -> new HashMap<>()) - .compute(source.getControllerId(), CardUtil::setOrIncrementValue); - } - - void addPlayFromAnywhereEffect(UUID uuid) { - playFromAnywhereEffectId = uuid; - } - - UUID getPlayFromAnywhereEffect() { - return playFromAnywhereEffectId; - } - - @Override - public void reset() { - morMap.clear(); - super.reset(); - } - -} - -class AddSubtypeEnteringCreatureEffect extends ReplacementEffectImpl { - - private final MageObjectReference mor; - private final SubType subType; - - AddSubtypeEnteringCreatureEffect(MageObjectReference mor, SubType subType, Outcome outcome) { - super(Duration.WhileOnBattlefield, outcome); - this.mor = mor; - this.subType = subType; - } - - private AddSubtypeEnteringCreatureEffect(final AddSubtypeEnteringCreatureEffect effect) { - super(effect); - this.mor = effect.mor; - this.subType = effect.subType; - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CAST_SPELL_LATE; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - MageObject spell = game.getObject(event.getSourceId()); - return spell != null && mor.refersTo(spell, game); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Spell target = game.getSpell(event.getSourceId()); - if (target != null) { - AddCardSubTypeEnteringTargetEffect effect = new AddCardSubTypeEnteringTargetEffect(mor, subType, Duration.WhileOnBattlefield); - effect.setTargetPointer(new FixedTarget(target, game)); - game.addEffect(effect, source); - } - return false; - } - - @Override - public AddSubtypeEnteringCreatureEffect copy() { - return new AddSubtypeEnteringCreatureEffect(this); - } -} - -class AddCardSubTypeEnteringTargetEffect extends ContinuousEffectImpl { - - private final SubType addedSubType; - private final MageObjectReference mor; - private Card card; - - AddCardSubTypeEnteringTargetEffect(MageObjectReference mor, SubType addedSubType, Duration duration) { - super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - this.addedSubType = addedSubType; - this.mor = mor; - } - - protected AddCardSubTypeEnteringTargetEffect(final AddCardSubTypeEnteringTargetEffect effect) { - super(effect); - this.addedSubType = effect.addedSubType; - this.mor = effect.mor; - this.card = effect.card; - } - - @Override - public boolean apply(Game game, Ability source) { - Spell spell = game.getSpell(getTargetPointer().getFirst(game, source)); - MageObject target = game.getObject(getTargetPointer().getFirst(game, source)); - if (spell != null) { - card = spell.getCard(); - } - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell - && target != null - && target.equals(stackObject) - && mor.refersTo(target, game)) { - setCreatureSubtype(stackObject, addedSubType, game); - setCreatureSubtype(((Spell) stackObject).getCard(), addedSubType, game); - } - } - if (card != null - && game.getPermanent(card.getId()) != null - && game.getState().getZoneChangeCounter(card.getId()) == mor.getZoneChangeCounter() + 1) { // blinking, etc - game.getPermanent(card.getId()).addSubType(game, addedSubType); - } - return true; - } - - private void setCreatureSubtype(MageObject object, SubType subtype, Game game) { - SubTypes subTypes = game.getState().getCreateMageObjectAttribute(object, game).getSubtype(); - if (!subTypes.contains(subtype)) { - subTypes.add(subtype); - } - } - - @Override - public AddCardSubTypeEnteringTargetEffect copy() { - return new AddCardSubTypeEnteringTargetEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheTrueScriptures.java b/Mage.Sets/src/mage/cards/t/TheTrueScriptures.java deleted file mode 100644 index d29aba1a894..00000000000 --- a/Mage.Sets/src/mage/cards/t/TheTrueScriptures.java +++ /dev/null @@ -1,114 +0,0 @@ -package mage.cards.t; - -import mage.abilities.Ability; -import mage.abilities.common.SagaAbility; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; -import mage.abilities.effects.common.MillCardsEachPlayerEffect; -import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; -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.players.Player; -import mage.target.common.TargetCreatureOrPlaneswalker; -import mage.target.targetadjustment.ForEachPlayerTargetsAdjuster; -import mage.target.targetpointer.EachTargetPointer; - -import java.util.Collection; -import java.util.Objects; -import java.util.UUID; -import java.util.stream.Collectors; - -/** - * @author TheElk801 - */ -public final class TheTrueScriptures extends CardImpl { - - public TheTrueScriptures(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.SAGA); - this.color.setBlack(true); - this.nightCard = true; - - // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); - - // I -- For each opponent, destroy up to one target creature or planeswalker that player controls. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, false, - ability -> { - ability.addEffect(new DestroyTargetEffect().setTargetPointer(new EachTargetPointer()) - .setText("for each opponent, destroy up to one target creature or planeswalker that player controls")); - ability.addTarget(new TargetCreatureOrPlaneswalker(0,1)); - ability.setTargetAdjuster(new ForEachPlayerTargetsAdjuster(false, true)); - } - ); - - // II -- Each opponent discards three cards, then mills three cards. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_II, - new DiscardEachPlayerEffect(StaticValue.get(3), false, TargetController.OPPONENT), - new MillCardsEachPlayerEffect(3, TargetController.OPPONENT).setText(", then mills three cards") - ); - - // III -- Put all creature cards from all graveyards onto the battlefield under your control. Exile The True Scriptures, then return it to the battlefield. - sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_III, - new TheTrueScripturesEffect(), - new ExileSourceAndReturnFaceUpEffect() - ); - this.addAbility(sagaAbility); - } - - private TheTrueScriptures(final TheTrueScriptures card) { - super(card); - } - - @Override - public TheTrueScriptures copy() { - return new TheTrueScriptures(this); - } -} - -class TheTrueScripturesEffect extends OneShotEffect { - - TheTrueScripturesEffect() { - super(Outcome.Benefit); - staticText = "put all creature cards from all graveyards onto the battlefield under your control"; - } - - private TheTrueScripturesEffect(final TheTrueScripturesEffect effect) { - super(effect); - } - - @Override - public TheTrueScripturesEffect copy() { - return new TheTrueScripturesEffect(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 - .getState() - .getPlayersInRange(source.getControllerId(), game) - .stream() - .map(game::getPlayer) - .filter(Objects::nonNull) - .map(Player::getGraveyard) - .map(gy -> gy.getCards(StaticFilters.FILTER_CARD_CREATURE, game)) - .flatMap(Collection::stream) - .collect(Collectors.toList())); - return player.moveCards(cards, Zone.BATTLEFIELD, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheUnagiOfKyoshiIsland.java b/Mage.Sets/src/mage/cards/t/TheUnagiOfKyoshiIsland.java new file mode 100644 index 00000000000..0474f6d5631 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheUnagiOfKyoshiIsland.java @@ -0,0 +1,52 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.WardAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheUnagiOfKyoshiIsland extends CardImpl { + + public TheUnagiOfKyoshiIsland(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.SERPENT); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Ward--Waterbend {4} + this.addAbility(new WardAbility(new WaterbendCost(4))); + + // Whenever an opponent draws their second card each turn, draw two cards. + this.addAbility(new DrawNthCardTriggeredAbility( + new DrawCardSourceControllerEffect(2), + false, TargetController.OPPONENT, 2 + )); + } + + private TheUnagiOfKyoshiIsland(final TheUnagiOfKyoshiIsland card) { + super(card); + } + + @Override + public TheUnagiOfKyoshiIsland copy() { + return new TheUnagiOfKyoshiIsland(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheWallsOfBaSingSe.java b/Mage.Sets/src/mage/cards/t/TheWallsOfBaSingSe.java new file mode 100644 index 00000000000..81469195cc6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheWallsOfBaSingSe.java @@ -0,0 +1,49 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.IndestructibleAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheWallsOfBaSingSe extends CardImpl { + + public TheWallsOfBaSingSe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{8}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(30); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Other permanents you control have indestructible. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENTS, true + ))); + } + + private TheWallsOfBaSingSe(final TheWallsOfBaSingSe card) { + super(card); + } + + @Override + public TheWallsOfBaSingSe copy() { + return new TheWallsOfBaSingSe(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThingInTheIce.java b/Mage.Sets/src/mage/cards/t/ThingInTheIce.java index 149beca63ac..e0f3f72026d 100644 --- a/Mage.Sets/src/mage/cards/t/ThingInTheIce.java +++ b/Mage.Sets/src/mage/cards/t/ThingInTheIce.java @@ -1,24 +1,25 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterSpell; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import java.util.UUID; @@ -26,36 +27,39 @@ import java.util.UUID; /** * @author fireshoes */ -public final class ThingInTheIce extends CardImpl { +public final class ThingInTheIce extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("an instant or sorcery spell"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("non-Horror creatures"); static { filter.add(Predicates.or( CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); + filter2.add(Predicates.not(SubType.HORROR.getPredicate())); } private static final Condition condition = new SourceHasCounterCondition(CounterType.ICE, ComparisonType.EQUAL_TO, 0); public ThingInTheIce(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(0); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HORROR}, "{1}{U}", + "Awoken Horror", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.KRAKEN, SubType.HORROR}, "U" + ); - this.secondSideCardClazz = mage.cards.a.AwokenHorror.class; + // Thing in the Ice + this.getLeftHalfCard().setPT(0, 4); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // Thing in the Ice enters the battlefield with four ice counters on it. - this.addAbility(new EntersBattlefieldAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.ICE.createInstance(4)).setText("with four ice counters on it") )); // Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. Then if it has no ice counters on it, transform it. - this.addAbility(new TransformAbility()); Ability ability = new SpellCastControllerTriggeredAbility( new RemoveCounterSourceEffect(CounterType.ICE.createInstance(1)), filter, false ); @@ -63,7 +67,13 @@ public final class ThingInTheIce extends CardImpl { new TransformSourceEffect(), condition, "Then if it has no ice counters on it, transform it" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Awoken Horror + this.getRightHalfCard().setPT(7, 8); + + // When this creature transforms into Awoken Horrow, return all non-Horror creatures to their owners' hands. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter2))); } private ThingInTheIce(final ThingInTheIce card) { diff --git a/Mage.Sets/src/mage/cards/t/ThousandMoonsSmithy.java b/Mage.Sets/src/mage/cards/t/ThousandMoonsSmithy.java index 7a5010aca01..d499844897d 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandMoonsSmithy.java +++ b/Mage.Sets/src/mage/cards/t/ThousandMoonsSmithy.java @@ -1,16 +1,19 @@ package mage.cards.t; -import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +import mage.abilities.common.CastSpellPaidBySourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.WhiteManaAbility; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.FilterSpell; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; @@ -22,36 +25,55 @@ import java.util.UUID; /** * @author Susucr */ -public final class ThousandMoonsSmithy extends CardImpl { +public final class ThousandMoonsSmithy extends TransformingDoubleFacedCard { public static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped artifacts and/or creatures you control"); + private static final FilterSpell filter2 = new FilterSpell("an artifact or creature spell"); + static { filter.add(TappedPredicate.UNTAPPED); filter.add(Predicates.or( CardType.CREATURE.getPredicate(), CardType.ARTIFACT.getPredicate() )); + filter2.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); } public ThousandMoonsSmithy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}{W}"); - this.secondSideCardClazz = mage.cards.b.BarracksOfTheThousand.class; - - this.supertype.add(SuperType.LEGENDARY); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{W}{W}", + "Barracks of the Thousand", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.LAND}, new SubType[]{}, "" + ); + // Thousand Moons Smithy // When Thousand Moons Smithy enters the battlefield, create a white Gnome Soldier artifact creature token with "This creature's power and toughness are each equal to the number of artifacts and/or creatures you control." - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeSoldierStarStarToken()))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GnomeSoldierStarStarToken()))); // At the beginning of your precombat main phase, you may tap five untapped artifacts and/or creatures you control. If you do, transform Thousand Moons Smithy. - this.addAbility(new TransformAbility()); - this.addAbility(new BeginningOfFirstMainTriggeredAbility( + this.getLeftHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility( new DoIfCostPaid( new TransformSourceEffect(), new TapTargetCost(new TargetControlledPermanent(5, filter)) ) )); + + // Barracks of the Thousand + // (Transforms from Thousand Moons Smithy.) + + // {T}: Add {W}. + this.getRightHalfCard().addAbility(new WhiteManaAbility()); + + // Whenever you cast an artifact or creature spell using mana produced by Barracks of the Thousand, create a white Gnome Soldier artifact creature token with "This creature's power and toughness are each equal to the number of artifacts and/or creatures you control." + this.getRightHalfCard().addAbility(new CastSpellPaidBySourceTriggeredAbility( + new CreateTokenEffect(new GnomeSoldierStarStarToken()), + filter2, false + )); } private ThousandMoonsSmithy(final ThousandMoonsSmithy card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrabenGargoyle.java b/Mage.Sets/src/mage/cards/t/ThrabenGargoyle.java index 58d9fdb799e..4296d7dc735 100644 --- a/Mage.Sets/src/mage/cards/t/ThrabenGargoyle.java +++ b/Mage.Sets/src/mage/cards/t/ThrabenGargoyle.java @@ -1,39 +1,43 @@ - package mage.cards.t; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; + +import java.util.UUID; /** * @author fireshoes */ -public final class ThrabenGargoyle extends CardImpl { +public final class ThrabenGargoyle extends TransformingDoubleFacedCard { public ThrabenGargoyle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); - this.subtype.add(SubType.GARGOYLE); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GARGOYLE}, "{1}", + "Stonewing Antagonizer", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GARGOYLE, SubType.HORROR}, "" + ); - this.secondSideCardClazz = mage.cards.s.StonewingAntagonizer.class; + // Thraben Gargoyle + this.getLeftHalfCard().setPT(2, 2); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {6}: Transform Thraben Gargoyle. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(6))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(6))); + + // Stonewing Antagonizer + this.getRightHalfCard().setPT(4, 2); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); } private ThrabenGargoyle(final ThrabenGargoyle card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrabenMilitia.java b/Mage.Sets/src/mage/cards/t/ThrabenMilitia.java deleted file mode 100644 index d9998dc5920..00000000000 --- a/Mage.Sets/src/mage/cards/t/ThrabenMilitia.java +++ /dev/null @@ -1,40 +0,0 @@ - -package mage.cards.t; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author nantuko - */ -public final class ThrabenMilitia extends CardImpl { - - public ThrabenMilitia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); - this.color.setWhite(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - this.addAbility(TrampleAbility.getInstance()); - } - - private ThrabenMilitia(final ThrabenMilitia card) { - super(card); - } - - @Override - public ThrabenMilitia copy() { - return new ThrabenMilitia(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/ThrabenSentry.java b/Mage.Sets/src/mage/cards/t/ThrabenSentry.java index 7ccaf78bd07..c4e6be3c500 100644 --- a/Mage.Sets/src/mage/cards/t/ThrabenSentry.java +++ b/Mage.Sets/src/mage/cards/t/ThrabenSentry.java @@ -1,38 +1,41 @@ - package mage.cards.t; -import java.util.UUID; -import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** * @author nantuko */ -public final class ThrabenSentry extends CardImpl { +public final class ThrabenSentry extends TransformingDoubleFacedCard { public ThrabenSentry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SOLDIER); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "{3}{W}", + "Thraben Militia", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SOLDIER}, "W" + ); - this.secondSideCardClazz = mage.cards.t.ThrabenMilitia.class; + // Thraben Sentry + this.getLeftHalfCard().setPT(2, 2); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Whenever another creature you control dies, you may transform Thraben Sentry. - this.addAbility(new TransformAbility()); - this.addAbility(new DiesCreatureTriggeredAbility(new TransformSourceEffect(), true, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(new TransformSourceEffect(), true, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)); + + // Thraben Militia + this.getRightHalfCard().setPT(5, 4); + + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); } private ThrabenSentry(final ThrabenSentry card) { diff --git a/Mage.Sets/src/mage/cards/t/ThroneOfTheGrimCaptain.java b/Mage.Sets/src/mage/cards/t/ThroneOfTheGrimCaptain.java index 9a668ec3be6..8df9d2898d1 100644 --- a/Mage.Sets/src/mage/cards/t/ThroneOfTheGrimCaptain.java +++ b/Mage.Sets/src/mage/cards/t/ThroneOfTheGrimCaptain.java @@ -2,27 +2,32 @@ package mage.cards.t; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.assignment.common.SubTypeAssignment; +import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.assignment.common.SubTypeAssignment; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; -import mage.abilities.keyword.CraftAbility; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.keyword.*; 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.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; +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; import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; +import mage.util.CardUtil; import java.util.Objects; import java.util.Set; @@ -32,19 +37,41 @@ import java.util.stream.Collectors; /** * @author TheElk801 */ -public final class ThroneOfTheGrimCaptain extends CardImpl { +public final class ThroneOfTheGrimCaptain extends TransformingDoubleFacedCard { public ThroneOfTheGrimCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.t.TheGrimCaptain.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "The Grim Captain", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SKELETON, SubType.SPIRIT, SubType.PIRATE}, "B" + ); + // Throne of the Grim Captain // {T}: Mill two cards. - this.addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(2), new TapSourceCost())); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(2), new TapSourceCost())); // Craft with a Dinosaur, a Merfolk, a Pirate, and a Vampire {4} - this.addAbility(new CraftAbility("{4}", "a Dinosaur, a Merfolk, a Pirate, and a Vampire", new ThroneOfTheGrimCaptainTarget())); + this.getLeftHalfCard().addAbility(new CraftAbility("{4}", "a Dinosaur, a Merfolk, a Pirate, and a Vampire", new ThroneOfTheGrimCaptainTarget())); + + // The Grim Captain + this.getRightHalfCard().setPT(7, 7); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Hexproof + this.getRightHalfCard().addAbility(HexproofAbility.getInstance()); + + // Whenever The Grim Captain attacks, each opponent sacrifices a nonland permanent. Then you may put an exiled creature card used to craft The Grim Captain onto the battlefield under your control tapped and attacking. + Ability ability = new AttacksTriggeredAbility(new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_NON_LAND)); + ability.addEffect(new TheGrimCaptainEffect()); + this.getRightHalfCard().addAbility(ability); } private ThroneOfTheGrimCaptain(final ThroneOfTheGrimCaptain card) { @@ -109,3 +136,46 @@ class ThroneOfTheGrimCaptainTarget extends TargetCardInGraveyardBattlefieldOrSta return subtypeAssigner.getRoleCount(cards, game) <= 4; } } + +class TheGrimCaptainEffect extends OneShotEffect { + + TheGrimCaptainEffect() { + super(Outcome.Benefit); + staticText = "Then you may put an exiled creature card used to craft {this} " + + "onto the battlefield under your control tapped and attacking"; + } + + private TheGrimCaptainEffect(final TheGrimCaptainEffect effect) { + super(effect); + } + + @Override + public TheGrimCaptainEffect copy() { + return new TheGrimCaptainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInExile( + 0, 1, StaticFilters.FILTER_CARD_CREATURE, + CardUtil.getExileZoneId(game, source, -2) + ); + target.withNotTarget(true); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent == null) { + return false; + } + game.getCombat().addAttackingCreature(card.getId(), game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TicketBoothTunnelOfHate.java b/Mage.Sets/src/mage/cards/t/TicketBoothTunnelOfHate.java new file mode 100644 index 00000000000..8eff7e5a755 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TicketBoothTunnelOfHate.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.target.common.TargetAttackingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TicketBoothTunnelOfHate extends RoomCard { + + public TicketBoothTunnelOfHate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{R}", "{4}{R}{R}"); + + // Ticket Booth + // When you unlock this door, manifest dread. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new ManifestDreadEffect(), false, true)); + + // Tunnel of Hate + // Whenever you attack, target attacking creature gains double strike until end of turn. + Ability ability = new AttacksWithCreaturesTriggeredAbility(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()), 1); + ability.addTarget(new TargetAttackingCreature()); + this.getRightHalfCard().addAbility(ability); + } + + private TicketBoothTunnelOfHate(final TicketBoothTunnelOfHate card) { + super(card); + } + + @Override + public TicketBoothTunnelOfHate copy() { + return new TicketBoothTunnelOfHate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TigerDillo.java b/Mage.Sets/src/mage/cards/t/TigerDillo.java new file mode 100644 index 00000000000..ba03f8c3142 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TigerDillo.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.MageInt; +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.hint.ConditionHint; +import mage.abilities.hint.Hint; +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.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TigerDillo extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("you control another creature with power 4 or greater"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition); + + public TigerDillo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.ARMADILLO); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // This creature can't attack or block unless you control another creature with power 4 or greater. + this.addAbility(new SimpleStaticAbility(new CantAttackBlockUnlessConditionSourceEffect(condition)).addHint(hint)); + } + + private TigerDillo(final TigerDillo card) { + super(card); + } + + @Override + public TigerDillo copy() { + return new TigerDillo(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TigerSeal.java b/Mage.Sets/src/mage/cards/t/TigerSeal.java new file mode 100644 index 00000000000..b6e6980a4a0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TigerSeal.java @@ -0,0 +1,47 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; +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 TigerSeal extends CardImpl { + + public TigerSeal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.SEAL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // At the beginning of your upkeep, tap this creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TapSourceEffect())); + + // Whenever you draw your second card each turn, untap this creature. + this.addAbility(new DrawNthCardTriggeredAbility(new UntapSourceEffect())); + } + + private TigerSeal(final TigerSeal card) { + super(card); + } + + @Override + public TigerSeal copy() { + return new TigerSeal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TimberShredder.java b/Mage.Sets/src/mage/cards/t/TimberShredder.java deleted file mode 100644 index 6fe22125f0b..00000000000 --- a/Mage.Sets/src/mage/cards/t/TimberShredder.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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 fireshoes - */ -public final class TimberShredder extends CardImpl { - - public TimberShredder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(2); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private TimberShredder(final TimberShredder card) { - super(card); - } - - @Override - public TimberShredder copy() { - return new TimberShredder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java b/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java index 83473f261c3..b26b3873ca8 100644 --- a/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java +++ b/Mage.Sets/src/mage/cards/t/TinybonesBaubleBurglar.java @@ -213,8 +213,8 @@ class TinybonesBaubleBurglarSpendAnyManaEffect extends AsThoughEffectImpl implem cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } else if (card instanceof CardWithSpellOption) { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); - } else if (card instanceof ModalDoubleFacedCard) { - cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); + } else if (card instanceof DoubleFacedCard) { + cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED); } else { cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); } diff --git a/Mage.Sets/src/mage/cards/t/TirelessHauler.java b/Mage.Sets/src/mage/cards/t/TirelessHauler.java index 4f3cb398b9a..ec32a2f125e 100644 --- a/Mage.Sets/src/mage/cards/t/TirelessHauler.java +++ b/Mage.Sets/src/mage/cards/t/TirelessHauler.java @@ -1,10 +1,10 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +13,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TirelessHauler extends CardImpl { +public final class TirelessHauler extends TransformingDoubleFacedCard { public TirelessHauler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}", + "Dire-Strain Brawler", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(5); - this.secondSideCardClazz = mage.cards.d.DireStrainBrawler.class; + // Tireless Hauler + this.getLeftHalfCard().setPT(4, 5); // Vigilance - this.addAbility(VigilanceAbility.getInstance()); + this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Dire-Strain Brawler + this.getRightHalfCard().setPT(6, 6); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private TirelessHauler(final TirelessHauler card) { diff --git a/Mage.Sets/src/mage/cards/t/TitanHunter.java b/Mage.Sets/src/mage/cards/t/TitanHunter.java index 4697836741b..88087d5b0af 100644 --- a/Mage.Sets/src/mage/cards/t/TitanHunter.java +++ b/Mage.Sets/src/mage/cards/t/TitanHunter.java @@ -39,7 +39,7 @@ public final class TitanHunter extends CardImpl { // At the beginning of each player's end step, if no creatures died this turn, Titan Hunter deals 4 damage to that player. this.addAbility(new BeginningOfEndStepTriggeredAbility( TargetController.EACH_PLAYER, - new DamageTargetEffect(4, true, "that player"), + new DamageTargetEffect(4).withTargetDescription("that player"), false, condition ).addHint(MorbidHint.instance)); diff --git a/Mage.Sets/src/mage/cards/t/TithingBlade.java b/Mage.Sets/src/mage/cards/t/TithingBlade.java index 4ef97edc81b..409425b040d 100644 --- a/Mage.Sets/src/mage/cards/t/TithingBlade.java +++ b/Mage.Sets/src/mage/cards/t/TithingBlade.java @@ -1,11 +1,16 @@ package mage.cards.t; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; import java.util.UUID; @@ -13,22 +18,34 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TithingBlade extends CardImpl { +public final class TithingBlade extends TransformingDoubleFacedCard { public TithingBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); - this.secondSideCardClazz = mage.cards.c.ConsumingSepulcher.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{B}", + "Consuming Sepulcher", + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "B" + ); + // Tithing Blade // When Tithing Blade enters the battlefield, each opponent sacrifices a creature. - this.addAbility(new EntersBattlefieldTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility( new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_CREATURE) )); // Craft with creature {4}{B} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{4}{B}", "creature", "another creature you control " + "or a creature card in your graveyard", CardType.CREATURE.getPredicate()) ); + + // Consuming Sepulcher + // At the beginning of your upkeep, each opponent loses 1 life and you gain 1 life. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new LoseLifeOpponentsEffect(1) + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.getRightHalfCard().addAbility(ability); } private TithingBlade(final TithingBlade card) { diff --git a/Mage.Sets/src/mage/cards/t/TollsOfWar.java b/Mage.Sets/src/mage/cards/t/TollsOfWar.java new file mode 100644 index 00000000000..1e113a7cef3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TollsOfWar.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.condition.common.MyTurnCondition; +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.AllyToken; +import mage.game.permanent.token.ClueArtifactToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TollsOfWar extends CardImpl { + + public TollsOfWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{B}"); + + // When this enchantment enters, create a Clue token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken()))); + + // Whenever you sacrifice a permanent during your turn, create a 1/1 white Ally creature token. This ability triggers only once each turn. + this.addAbility(new SacrificePermanentTriggeredAbility( + new CreateTokenEffect(new AllyToken()), StaticFilters.FILTER_PERMANENT + ).withTriggerCondition(MyTurnCondition.instance).setTriggersLimitEachTurn(1)); + } + + private TollsOfWar(final TollsOfWar card) { + super(card); + } + + @Override + public TollsOfWar copy() { + return new TollsOfWar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TombOfTheDuskRose.java b/Mage.Sets/src/mage/cards/t/TombOfTheDuskRose.java deleted file mode 100644 index 46a7ecf9733..00000000000 --- a/Mage.Sets/src/mage/cards/t/TombOfTheDuskRose.java +++ /dev/null @@ -1,91 +0,0 @@ -package mage.cards.t; - -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.mana.AnyColorManaAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; -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.util.CardUtil; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class TombOfTheDuskRose extends CardImpl { - - public TombOfTheDuskRose(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // (Transforms from Profane Procession.) - - // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - - // {2}{W}{B},{T} : Put a creature card exiled with this permanent onto the battlefield under your control. - Ability ability = new SimpleActivatedAbility(new TombOfTheDuskRoseEffect(), new ManaCostsImpl<>("{2}{W}{B}")); - ability.addCost(new TapSourceCost()); - this.addAbility(ability); - } - - private TombOfTheDuskRose(final TombOfTheDuskRose card) { - super(card); - } - - @Override - public TombOfTheDuskRose copy() { - return new TombOfTheDuskRose(this); - } -} - -class TombOfTheDuskRoseEffect extends OneShotEffect { - - TombOfTheDuskRoseEffect() { - super(Outcome.PutCardInPlay); - this.staticText = "put a creature card exiled with this permanent onto the battlefield under your control"; - } - - private TombOfTheDuskRoseEffect(final TombOfTheDuskRoseEffect effect) { - super(effect); - } - - @Override - public TombOfTheDuskRoseEffect copy() { - return new TombOfTheDuskRoseEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); - if (exileZone == null || exileZone.count(StaticFilters.FILTER_CARD_CREATURE, game) < 1) { - return false; - } - TargetCard targetCard = new TargetCardInExile(StaticFilters.FILTER_CARD_CREATURE, exileZone.getId()); - targetCard.withNotTarget(true); - controller.choose(outcome, targetCard, source, game); - Card card = game.getCard(targetCard.getFirstTarget()); - return card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java b/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java new file mode 100644 index 00000000000..b47049de3fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TophEarthbendingMaster.java @@ -0,0 +1,58 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.common.LandfallAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersControllerCount; +import mage.abilities.effects.common.counter.AddCountersPlayersEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TophEarthbendingMaster extends CardImpl { + + private static final DynamicValue xValue = new CountersControllerCount(CounterType.EXPERIENCE); + + public TophEarthbendingMaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Landfall -- Whenever a land you control enters, you get an experience counter. + this.addAbility(new LandfallAbility(new AddCountersPlayersEffect( + CounterType.EXPERIENCE.createInstance(), TargetController.YOU + ))); + + // Whenever you attack, earthbend X, where X is the number of experience counters you have. + Ability ability = new AttacksWithCreaturesTriggeredAbility(new EarthbendTargetEffect(xValue, true), 1); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private TophEarthbendingMaster(final TophEarthbendingMaster card) { + super(card); + } + + @Override + public TophEarthbendingMaster copy() { + return new TophEarthbendingMaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java b/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java new file mode 100644 index 00000000000..7a0d5fc3fa5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TophGreatestEarthbender.java @@ -0,0 +1,63 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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 mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TophGreatestEarthbender extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("land creatures"); + + static { + filter.add(CardType.LAND.getPredicate()); + filter.add(CardType.CREATURE.getPredicate()); + } + + public TophGreatestEarthbender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Toph enters, earthbend X, where X is the amount of mana spent to cast her. + Ability ability = new EntersBattlefieldTriggeredAbility(new EarthbendTargetEffect(ManaSpentToCastCount.instance, true)); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + + // Land creatures you control have double strike. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + } + + private TophGreatestEarthbender(final TophGreatestEarthbender card) { + super(card); + } + + @Override + public TophGreatestEarthbender copy() { + return new TophGreatestEarthbender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java b/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java new file mode 100644 index 00000000000..7d47a19656e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TophHardheadedTeacher.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.keyword.EarthbendTargetEffect; +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.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TophHardheadedTeacher extends CardImpl { + + public TophHardheadedTeacher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Toph enters, you may discard a card. If you do, return target instant or sorcery card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new DiscardCardCost()) + ); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // Whenever you cast a spell, earthbend 1. If that spell is a Lesson, put an additional +1/+1 counter on that land. + ability = new SpellCastControllerTriggeredAbility(new EarthbendTargetEffect(1), false); + ability.addEffect(new TophHardheadedTeacherEffect()); + ability.addTarget(new TargetControlledLandPermanent()); + this.addAbility(ability); + } + + private TophHardheadedTeacher(final TophHardheadedTeacher card) { + super(card); + } + + @Override + public TophHardheadedTeacher copy() { + return new TophHardheadedTeacher(this); + } +} + +class TophHardheadedTeacherEffect extends OneShotEffect { + + TophHardheadedTeacherEffect() { + super(Outcome.Benefit); + staticText = "If that spell is a Lesson, put an additional +1/+1 counter on that land"; + } + + private TophHardheadedTeacherEffect(final TophHardheadedTeacherEffect effect) { + super(effect); + } + + @Override + public TophHardheadedTeacherEffect copy() { + return new TophHardheadedTeacherEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) getValue("spellCast"); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return spell != null && permanent != null + && spell.hasSubtype(SubType.LESSON, game) + && permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TormentedPariah.java b/Mage.Sets/src/mage/cards/t/TormentedPariah.java index 7d5997a1c5c..9dfea2e28e3 100644 --- a/Mage.Sets/src/mage/cards/t/TormentedPariah.java +++ b/Mage.Sets/src/mage/cards/t/TormentedPariah.java @@ -1,10 +1,9 @@ package mage.cards.t; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +12,26 @@ import java.util.UUID; /** * @author nantuko */ -public final class TormentedPariah extends CardImpl { +public final class TormentedPariah extends TransformingDoubleFacedCard { public TormentedPariah(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARRIOR); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARRIOR, SubType.WEREWOLF}, "{3}{R}", + "Rampaging Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.r.RampagingWerewolf.class; - - this.power = new MageInt(3); - this.toughness = new MageInt(2); + // Tormented Pariah + this.getLeftHalfCard().setPT(3, 2); // At the beginning of each upkeep, if no spells were cast last turn, transform Tormented Pariah. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Rampaging Werewolf + this.getRightHalfCard().setPT(6, 4); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Rampaging Werewolf. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private TormentedPariah(final TormentedPariah card) { diff --git a/Mage.Sets/src/mage/cards/t/ToucanPuffin.java b/Mage.Sets/src/mage/cards/t/ToucanPuffin.java new file mode 100644 index 00000000000..f3b285f6c41 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ToucanPuffin.java @@ -0,0 +1,45 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ToucanPuffin extends CardImpl { + + public ToucanPuffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When this creature enters, target creature you control gets +2/+0 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ToucanPuffin(final ToucanPuffin card) { + super(card); + } + + @Override + public ToucanPuffin copy() { + return new ToucanPuffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java index 38c837a9a2b..704e701d151 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java +++ b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java @@ -1,19 +1,26 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; 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.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; +import mage.abilities.keyword.TrampleAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; @@ -28,41 +35,68 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TovolarDireOverlord extends CardImpl { +public final class TovolarDireOverlord extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more Wolves and/or Werewolves"); + private static final FilterPermanent filter2 = new FilterControlledPermanent("a Wolf or Werewolf you control"); static { filter.add(Predicates.or( SubType.WOLF.getPredicate(), SubType.WEREWOLF.getPredicate() )); + filter2.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); private static final Hint hint = new ValueHint("Wolves and Werewolves you control", new PermanentsOnBattlefieldCount(filter)); public TovolarDireOverlord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{R}{G}", + "Tovolar, the Midnight Scourge", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.t.TovolarTheMidnightScourge.class; + // Tovolar, Dire Overlord + this.getLeftHalfCard().setPT(3, 3); // Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card. - this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( - new DrawCardSourceControllerEffect(1), filter, + this.getLeftHalfCard().addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter2, false, SetTargetPointer.NONE, true ).setTriggerPhrase("Whenever a Wolf or Werewolf you control deals combat damage to a player, ")); // At the beginning of your upkeep, if you control three or more Wolves and/or Werewolves, it becomes night. Then transform any number of Human Werewolves you control. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TovolarDireOverlordEffect()).withInterveningIf(condition).addHint(hint)); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TovolarDireOverlordEffect()).withInterveningIf(condition).addHint(hint)); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Tovolar, the Midnight Scourge + this.getRightHalfCard().setPT(4, 4); + + // Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card. + this.getRightHalfCard().addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter2, + false, SetTargetPointer.NONE, true + )); + + // {X}{R}{G}: Target Wolf or Werewolf you control gets +X/+0 and gains trample until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("Target Wolf or Werewolf you control gets +X/+0"), new ManaCostsImpl<>("{X}{R}{G}")); + ability.addEffect(new BoostTargetEffect( + GetXValue.instance, StaticValue.get(0), Duration.EndOfTurn + ).setText("and gains trample until end of turn")); + ability.addTarget(new TargetPermanent(filter2)); + this.getRightHalfCard().addAbility(ability); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private TovolarDireOverlord(final TovolarDireOverlord card) { diff --git a/Mage.Sets/src/mage/cards/t/TovolarTheMidnightScourge.java b/Mage.Sets/src/mage/cards/t/TovolarTheMidnightScourge.java deleted file mode 100644 index 4f6a6f75d0a..00000000000 --- a/Mage.Sets/src/mage/cards/t/TovolarTheMidnightScourge.java +++ /dev/null @@ -1,78 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.GetXValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicates; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TovolarTheMidnightScourge extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledPermanent("a Wolf or Werewolf you control"); - - static { - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public TovolarTheMidnightScourge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card. - this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( - new DrawCardSourceControllerEffect(1), filter, - false, SetTargetPointer.NONE, true - )); - - // {X}{R}{G}: Target Wolf or Werewolf you control gets +X/+0 and gains trample until end of turn. - Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn - ).setText("Target Wolf or Werewolf you control gets +X/+0"), new ManaCostsImpl<>("{X}{R}{G}")); - ability.addEffect(new BoostTargetEffect( - GetXValue.instance, StaticValue.get(0), Duration.EndOfTurn - ).setText("and gains trample until end of turn")); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private TovolarTheMidnightScourge(final TovolarTheMidnightScourge card) { - super(card); - } - - @Override - public TovolarTheMidnightScourge copy() { - return new TovolarTheMidnightScourge(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TovolarsHuntmaster.java b/Mage.Sets/src/mage/cards/t/TovolarsHuntmaster.java index 4e075bb75b4..b6e3580e7c3 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarsHuntmaster.java +++ b/Mage.Sets/src/mage/cards/t/TovolarsHuntmaster.java @@ -1,36 +1,78 @@ package mage.cards.t; -import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.permanent.token.WolfToken; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class TovolarsHuntmaster extends CardImpl { +public final class TovolarsHuntmaster extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter + = new FilterControlledPermanent("another Wolf or Werewolf you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); + } public TovolarsHuntmaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}{G}", + "Tovolar's Packleader", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.secondSideCardClazz = mage.cards.t.TovolarsPackleader.class; + // Tovolar's Huntmaster + this.getLeftHalfCard().setPT(6, 6); // Whenever Tovolar's Huntmaster enters the battlefield, create two 2/2 green Wolf creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WolfToken(), 2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WolfToken(), 2))); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Tovolar's Packleader + this.getRightHalfCard().setPT(7, 7); + + // Whenever Tovolar's Packleader enters the battlefield or attacks, create two 2/2 green Wolf creature tokens. + this.getRightHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new CreateTokenEffect(new WolfToken(), 2) + )); + + // {2}{G}{G}: Another target Wolf or Werewolf you control fights target creature you don't control. + Ability ability = new SimpleActivatedAbility(new FightTargetsEffect().setText( + "another target Wolf or Werewolf you control fights target creature you don't control" + ), new ManaCostsImpl<>("{2}{G}{G}")); + ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.getRightHalfCard().addAbility(ability); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private TovolarsHuntmaster(final TovolarsHuntmaster card) { diff --git a/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java b/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java deleted file mode 100644 index 3879bc96f68..00000000000 --- a/Mage.Sets/src/mage/cards/t/TovolarsMagehunter.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.SpellCastOpponentTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SetTargetPointer; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author North - */ -public final class TovolarsMagehunter extends CardImpl { - - public TovolarsMagehunter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - - this.color.setRed(true); - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever an opponent casts a spell, Tovolar's Magehunter deals 2 damage to that player. - this.addAbility(new SpellCastOpponentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player"), - StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER - )); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Tovolar's Magehunter. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private TovolarsMagehunter(final TovolarsMagehunter card) { - super(card); - } - - @Override - public TovolarsMagehunter copy() { - return new TovolarsMagehunter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java b/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java deleted file mode 100644 index de4fc98fa8e..00000000000 --- a/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java +++ /dev/null @@ -1,75 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.FightTargetsEffect; -import mage.abilities.keyword.NightboundAbility; -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.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.permanent.token.WolfToken; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TovolarsPackleader extends CardImpl { - - private static final FilterPermanent filter - = new FilterControlledPermanent("another Wolf or Werewolf you control"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public TovolarsPackleader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Tovolar's Packleader enters the battlefield or attacks, create two 2/2 green Wolf creature tokens. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( - new CreateTokenEffect(new WolfToken(), 2) - )); - - // {2}{G}{G}: Another target Wolf or Werewolf you control fights target creature you don't control. - Ability ability = new SimpleActivatedAbility(new FightTargetsEffect().setText( - "another target Wolf or Werewolf you control fights target creature you don't control" - ), 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()); - } - - private TovolarsPackleader(final TovolarsPackleader card) { - super(card); - } - - @Override - public TovolarsPackleader copy() { - return new TovolarsPackleader(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java index 1ebe153eed6..ca84a843ccc 100644 --- a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java +++ b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java @@ -1,15 +1,17 @@ package mage.cards.t; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.AttacksEachCombatStaticAbility; 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.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; @@ -18,21 +20,31 @@ import java.util.UUID; /** * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ -public final class TownGossipmonger extends CardImpl { +public final class TownGossipmonger extends TransformingDoubleFacedCard { public TownGossipmonger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); - this.subtype.add(SubType.HUMAN); - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "{W}", + "Incited Rabble", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN}, "R" + ); - this.secondSideCardClazz = mage.cards.i.IncitedRabble.class; + // Town Gossipmonger + this.getLeftHalfCard().setPT(1, 1); // {T}, Tap an untapped creature you control: Transform Town Gossipmonger. - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new TransformSourceEffect(), new TapSourceCost()); ability.addCost(new TapTargetCost(StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURE)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Incited Rabble + this.getRightHalfCard().setPT(2, 3); + + // Incited Rabble attacks each combat if able. + this.getRightHalfCard().addAbility(new AttacksEachCombatStaticAbility()); + + // {2}: Incited Rabble gets +1/+0 until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{2}"))); } private TownGossipmonger(final TownGossipmonger card) { diff --git a/Mage.Sets/src/mage/cards/t/TranceKujaFateDefied.java b/Mage.Sets/src/mage/cards/t/TranceKujaFateDefied.java deleted file mode 100644 index c16551c9f7d..00000000000 --- a/Mage.Sets/src/mage/cards/t/TranceKujaFateDefied.java +++ /dev/null @@ -1,84 +0,0 @@ -package mage.cards.t; - -import java.util.Optional; -import java.util.UUID; -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.GameEvent; -import mage.util.CardUtil; - -/** - * @author balazskristof - */ -public final class TranceKujaFateDefied extends CardImpl { - - public TranceKujaFateDefied(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.AVATAR); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(4); - this.toughness = new MageInt(6); - - this.color.setBlack(true); - this.color.setRed(true); - - this.nightCard = true; - - // Flame Star -- If a Wizard you control would deal damage to a permanent or player, it deals double that damage instead. - this.addAbility(new SimpleStaticAbility(new TranceKujaFateDefiedEffect()).withFlavorWord("Flame Star")); - } - - private TranceKujaFateDefied(final TranceKujaFateDefied card) { - super(card); - } - - @Override - public TranceKujaFateDefied copy() { - return new TranceKujaFateDefied(this); - } -} - -class TranceKujaFateDefiedEffect extends ReplacementEffectImpl { - - TranceKujaFateDefiedEffect() { - super(Duration.WhileOnBattlefield, Outcome.Damage); - staticText = "If a Wizard you control would deal damage to a permanent or player, it deals double that damage instead."; - } - - private TranceKujaFateDefiedEffect(final TranceKujaFateDefiedEffect effect) { - super(effect); - } - - @Override - public TranceKujaFateDefiedEffect copy() { - return new TranceKujaFateDefiedEffect(this); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(GameEvent.EventType.DAMAGE_PLAYER) - || event.getType().equals(GameEvent.EventType.DAMAGE_PERMANENT); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return game.getControllerId(event.getSourceId()).equals(source.getControllerId()) - && Optional.ofNullable(game.getObject(event.getSourceId())) - .map(object -> object.hasSubtype(SubType.WIZARD, game)) - .orElse(false); - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(CardUtil.overflowMultiply(event.getAmount(), 2)); - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TreasureCove.java b/Mage.Sets/src/mage/cards/t/TreasureCove.java deleted file mode 100644 index 62aa078d389..00000000000 --- a/Mage.Sets/src/mage/cards/t/TreasureCove.java +++ /dev/null @@ -1,53 +0,0 @@ - -package mage.cards.t; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.mana.ColorlessManaAbility; -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 mage.target.common.TargetControlledPermanent; - -/** - * - * @author TheElk801 - */ -public final class TreasureCove extends CardImpl { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Treasure"); - - static { - filter.add(SubType.TREASURE.getPredicate()); - } - - public TreasureCove(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.nightCard = true; - - // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); - - // {T}, Sacrifice a Treasure: Draw a card. - Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(filter)); - this.addAbility(ability); - } - - private TreasureCove(final TreasureCove card) { - super(card); - } - - @Override - public TreasureCove copy() { - return new TreasureCove(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TreasureMap.java b/Mage.Sets/src/mage/cards/t/TreasureMap.java index 224fbd8290d..bfaedc3b592 100644 --- a/Mage.Sets/src/mage/cards/t/TreasureMap.java +++ b/Mage.Sets/src/mage/cards/t/TreasureMap.java @@ -4,19 +4,23 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.TreasureToken; import java.util.UUID; @@ -24,17 +28,24 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TreasureMap extends CardImpl { +public final class TreasureMap extends TransformingDoubleFacedCard { private static final Condition condition = new SourceHasCounterCondition(CounterType.LANDMARK, 3); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Treasure"); + + static { + filter.add(SubType.TREASURE.getPredicate()); + } public TreasureMap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - - this.secondSideCardClazz = mage.cards.t.TreasureCove.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}", + "Treasure Cove", + new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Treasure Map // {1}, {T}: Scry 1. Put a landmark counter on Treasure Map. Then if there are three or more landmark counters on it, remove those counters, transform Treasure Map, and create three colorless Treasure artifact tokens with "{T}, Sacrifice this artifact: Add one mana of any color." - this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(new ScryEffect(1, false), new ManaCostsImpl<>("{1}")); ability.addCost(new TapSourceCost()); ability.addEffect(new AddCountersSourceEffect(CounterType.LANDMARK.createInstance())); @@ -42,7 +53,16 @@ public final class TreasureMap extends CardImpl { new RemoveAllCountersSourceEffect(CounterType.LANDMARK), condition, "Then if there are three or " + "more landmark counters on it, remove those counters, transform {this}, and create three Treasure tokens" ).addEffect(new TransformSourceEffect()).addEffect(new CreateTokenEffect(new TreasureToken(), 3))); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Treasure Cove + // {T}: Add {C}. + this.getRightHalfCard().addAbility(new ColorlessManaAbility()); + + // {T}, Sacrifice a Treasure: Draw a card. + Ability ability2 = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()); + ability2.addCost(new SacrificeTargetCost(filter)); + this.getRightHalfCard().addAbility(ability2); } private TreasureMap(final TreasureMap card) { diff --git a/Mage.Sets/src/mage/cards/t/TreetopFreedomFighters.java b/Mage.Sets/src/mage/cards/t/TreetopFreedomFighters.java new file mode 100644 index 00000000000..3d1a1bffcf9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TreetopFreedomFighters.java @@ -0,0 +1,44 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TreetopFreedomFighters extends CardImpl { + + public TreetopFreedomFighters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When this creature enters, create a 1/1 white Ally creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new AllyToken()))); + } + + private TreetopFreedomFighters(final TreetopFreedomFighters card) { + super(card); + } + + @Override + public TreetopFreedomFighters copy() { + return new TreetopFreedomFighters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TributeToHorobi.java b/Mage.Sets/src/mage/cards/t/TributeToHorobi.java index 5ae827f0d1c..94b70c92b3c 100644 --- a/Mage.Sets/src/mage/cards/t/TributeToHorobi.java +++ b/Mage.Sets/src/mage/cards/t/TributeToHorobi.java @@ -1,15 +1,22 @@ package mage.cards.t; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SagaAbility; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.CreateTokenAllEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainControlAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SagaChapter; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.RatRogueToken; import java.util.UUID; @@ -17,28 +24,53 @@ import java.util.UUID; /** * @author weirddan455 */ -public final class TributeToHorobi extends CardImpl { +public final class TributeToHorobi extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterPermanent(SubType.RAT, "Rat tokens"); + + static { + filter.add(TokenPredicate.TRUE); + } public TributeToHorobi(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.e.EchoOfDeathsWail.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{B}", + "Echo of Death's Wail", + new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "B" + ); + // Tribute to Horobi // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I, II — Each opponent creates a 1/1 black Rat Rouge creature token. sagaAbility.addChapterEffect( - this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + this.getLeftHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, new CreateTokenAllEffect(new RatRogueToken(), TargetController.OPPONENT) ); // 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()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Echo of Death's Wail + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // When Echo of Death's Wail enters the battlefield, gain control of all Rat tokens. + this.getRightHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainControlAllEffect(Duration.Custom, filter))); + + // Whenever Echo of Death's Wail attacks, you may sacrifice another creature. If you do, draw a card. + this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), + new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) + ))); } private TributeToHorobi(final TributeToHorobi card) { diff --git a/Mage.Sets/src/mage/cards/t/TrickShot.java b/Mage.Sets/src/mage/cards/t/TrickShot.java index 9eeb2b6385f..e233fc090af 100644 --- a/Mage.Sets/src/mage/cards/t/TrickShot.java +++ b/Mage.Sets/src/mage/cards/t/TrickShot.java @@ -1,6 +1,6 @@ package mage.cards.t; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -9,7 +9,6 @@ import mage.filter.predicate.other.AnotherTargetPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.SecondTargetPointer; import java.util.UUID; @@ -31,12 +30,7 @@ public final class TrickShot extends CardImpl { // Trick Shot deals 6 damage to target creature and 2 damage to up to one other target creature token. this.getSpellAbility().addTarget(new TargetCreaturePermanent().setTargetTag(1)); this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter).setTargetTag(2)); - this.getSpellAbility().addEffect(new DamageTargetEffect(6, true, "", true)); - this.getSpellAbility().addEffect( - new DamageTargetEffect(2, true, "", true) - .setTargetPointer(new SecondTargetPointer()) - .setText("and 2 damage to up to one other target creature token") - ); + this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(6, 2)); } private TrickShot(final TrickShot card) { diff --git a/Mage.Sets/src/mage/cards/t/TrueAncestry.java b/Mage.Sets/src/mage/cards/t/TrueAncestry.java new file mode 100644 index 00000000000..43074a1e138 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrueAncestry.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.abilities.effects.common.CreateTokenEffect; +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.StaticFilters; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrueAncestry extends CardImpl { + + public TrueAncestry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + this.subtype.add(SubType.LESSON); + + // Return up to one target permanent card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_PERMANENT)); + + // Create a Clue token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new ClueArtifactToken()).concatBy("
")); + } + + private TrueAncestry(final TrueAncestry card) { + super(card); + } + + @Override + public TrueAncestry copy() { + return new TrueAncestry(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrugaCliffcharger.java b/Mage.Sets/src/mage/cards/t/TrugaCliffcharger.java deleted file mode 100644 index 79f4a82dd9c..00000000000 --- a/Mage.Sets/src/mage/cards/t/TrugaCliffcharger.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.t; - -import mage.MageInt; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.abilities.keyword.TrampleAbility; -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.TargetCardInLibrary; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TrugaCliffcharger extends CardImpl { - - private static final FilterCard filter = new FilterCard("a land or battle card"); - - static { - filter.add(Predicates.or( - CardType.LAND.getPredicate(), - CardType.BATTLE.getPredicate() - )); - } - - public TrugaCliffcharger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.RHINO); - this.power = new MageInt(3); - this.toughness = new MageInt(4); - this.color.setRed(true); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // When Truga Cliffcharger enters the battlefield, you may discard a card. If you do, search your library for a land or battle card, reveal it, put it into your hand, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new DoIfCostPaid(new SearchLibraryPutInHandEffect( - new TargetCardInLibrary(filter), true - ), new DiscardCardCost()) - )); - } - - private TrugaCliffcharger(final TrugaCliffcharger card) { - super(card); - } - - @Override - public TrugaCliffcharger copy() { - return new TrugaCliffcharger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java b/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java new file mode 100644 index 00000000000..e3f89637b55 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrustyBoomerang.java @@ -0,0 +1,91 @@ +package mage.cards.t; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +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.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Targets; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrustyBoomerang extends CardImpl { + + public TrustyBoomerang(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature has "{1}, {T}: Tap target creature. Return Trusty Boomerang to its owner's hand." + this.addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect( + "equipped creature has \"{1}, {T}: Tap target creature. Return {this} to its owner's hand.\"", + new Effects(new ReturnToHandTargetEffect(), new TrustyBoomerangEffect()), + new Targets(new TargetCreaturePermanent()), null, + new GenericManaCost(1), new TapSourceCost() + ))); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private TrustyBoomerang(final TrustyBoomerang card) { + super(card); + } + + @Override + public TrustyBoomerang copy() { + return new TrustyBoomerang(this); + } +} + +class TrustyBoomerangEffect extends OneShotEffect { + + TrustyBoomerangEffect() { + super(Outcome.Benefit); + } + + private TrustyBoomerangEffect(final TrustyBoomerangEffect effect) { + super(effect); + } + + @Override + public TrustyBoomerangEffect copy() { + return new TrustyBoomerangEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue("attachedPermanent"); + return player != null && permanent != null && player.moveCards(permanent, Zone.HAND, source, game); + } + + @Override + public String getText(Mode mode) { + return "return " + + Optional.ofNullable((Permanent) getValue("attachedPermanent")) + .map(MageObject::getName) + .orElse("Trusty Boomerang") + + " to its owner's hand"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrustyCompanion.java b/Mage.Sets/src/mage/cards/t/TrustyCompanion.java index 906a9baafd2..7a7c618f241 100644 --- a/Mage.Sets/src/mage/cards/t/TrustyCompanion.java +++ b/Mage.Sets/src/mage/cards/t/TrustyCompanion.java @@ -1,23 +1,24 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; 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 LevelX2 */ public final class TrustyCompanion extends CardImpl { public TrustyCompanion(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.HYENA); this.power = new MageInt(3); this.toughness = new MageInt(2); @@ -25,7 +26,7 @@ public final class TrustyCompanion extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); // Trusty Companion can't attack alone. - this.addAbility(new CantAttackAloneAbility()); + this.addAbility(new SimpleStaticAbility(new CantAttackAloneSourceEffect())); } private TrustyCompanion(final TrustyCompanion card) { diff --git a/Mage.Sets/src/mage/cards/t/TruthOrConsequences.java b/Mage.Sets/src/mage/cards/t/TruthOrConsequences.java index f919624b10f..1c10266bbb1 100644 --- a/Mage.Sets/src/mage/cards/t/TruthOrConsequences.java +++ b/Mage.Sets/src/mage/cards/t/TruthOrConsequences.java @@ -10,8 +10,9 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetOpponent; +import mage.util.RandomUtil; +import java.util.Optional; import java.util.UUID; /** @@ -64,10 +65,13 @@ class TruthOrConsequencesEffect extends OneShotEffect { TwoChoiceVote vote = new TwoChoiceVote("Truth (draw card)", "Consequences (deal damage)", Outcome.DrawCard, true); vote.doVotes(source, game); player.drawCards(vote.getVoteCount(true), source, game); - TargetOpponent target = new TargetOpponent(true); - target.setRandom(true); - target.choose(outcome, source.getControllerId(), source.getSourceId(), source, game); - Player opponent = game.getPlayer(target.getFirstTarget()); - return opponent == null || opponent.damage(3 * vote.getVoteCount(false), source, game) > 0; + Optional.of(game.getOpponents(player.getId(), true)) + .map(RandomUtil::randomFromCollection) + .map(game::getPlayer) + .ifPresent(opponent -> { + game.informPlayers(opponent.getLogName() + " has been chosen at random."); + opponent.damage(3 * vote.getVoteCount(false), source, game); + }); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TuiAndLaMoonAndOcean.java b/Mage.Sets/src/mage/cards/t/TuiAndLaMoonAndOcean.java new file mode 100644 index 00000000000..15d8b8d9953 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TuiAndLaMoonAndOcean.java @@ -0,0 +1,50 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.InspiredAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TuiAndLaMoonAndOcean extends CardImpl { + + public TuiAndLaMoonAndOcean(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.FISH); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Tui and La become tapped, draw a card. + this.addAbility(new BecomesTappedSourceTriggeredAbility(new DrawCardSourceControllerEffect(1)) + .setTriggerPhrase("Whenever {this} become tapped, ")); + + // Whenever Tui and La become untapped, put a +1/+1 counter on them. + this.addAbility(new InspiredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on them")) + .setTriggerPhrase("Whenever {this} become untapped, ") + .setAbilityWord(null)); + } + + private TuiAndLaMoonAndOcean(final TuiAndLaMoonAndOcean card) { + super(card); + } + + @Override + public TuiAndLaMoonAndOcean copy() { + return new TuiAndLaMoonAndOcean(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TundraTank.java b/Mage.Sets/src/mage/cards/t/TundraTank.java new file mode 100644 index 00000000000..4a354319b82 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TundraTank.java @@ -0,0 +1,50 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TundraTank extends CardImpl { + + public TundraTank(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // When this Vehicle enters, target creature you control gains indestructible until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(IndestructibleAbility.getInstance())); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private TundraTank(final TundraTank card) { + super(card); + } + + @Override + public TundraTank copy() { + return new TundraTank(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TwinBlades.java b/Mage.Sets/src/mage/cards/t/TwinBlades.java new file mode 100644 index 00000000000..d62bff46f3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TwinBlades.java @@ -0,0 +1,52 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAttachToTarget; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; +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 TwinBlades extends CardImpl { + + public TwinBlades(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When this Equipment enters, attach it to target creature you control. That creature gains double strike until end of turn. + Ability ability = new EntersBattlefieldAttachToTarget(); + ability.addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance()) + .setText("That creature gains double strike until end of turn")); + this.addAbility(ability); + + // Equipped creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private TwinBlades(final TwinBlades card) { + super(card); + } + + @Override + public TwinBlades copy() { + return new TwinBlades(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java b/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java index 3323597e51e..a85e49ad3bb 100644 --- a/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java +++ b/Mage.Sets/src/mage/cards/t/TwinbladeGeist.java @@ -1,35 +1,57 @@ package mage.cards.t; -import mage.MageInt; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DisturbAbility; import mage.abilities.keyword.DoubleStrikeAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.EnchantAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +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 TheElk801 */ -public final class TwinbladeGeist extends CardImpl { +public final class TwinbladeGeist extends TransformingDoubleFacedCard { public TwinbladeGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.WARRIOR}, "{1}{W}", + "Twinblade Invocation", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "W" + ); - this.subtype.add(SubType.SPIRIT); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.t.TwinbladeInvocation.class; + // Twinblade Geist + this.getLeftHalfCard().setPT(1, 1); // Double strike - this.addAbility(DoubleStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(DoubleStrikeAbility.getInstance()); // Disturb {2}{W} - this.addAbility(new DisturbAbility(this, "{2}{W}")); + this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{2}{W}")); + + // Twinblade Invocation + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // Enchanted creature has double strike. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + DoubleStrikeAbility.getInstance(), AttachmentType.AURA + ))); + + // If Twinblade Invocation would be put into a graveyard from anywhere, exile it instead. + this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility()); } private TwinbladeGeist(final TwinbladeGeist card) { diff --git a/Mage.Sets/src/mage/cards/t/TwinbladeInvocation.java b/Mage.Sets/src/mage/cards/t/TwinbladeInvocation.java deleted file mode 100644 index 1ade18bdba1..00000000000 --- a/Mage.Sets/src/mage/cards/t/TwinbladeInvocation.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.t; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.DisturbAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.EnchantAbility; -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.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class TwinbladeInvocation extends CardImpl { - - public TwinbladeInvocation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.subtype.add(SubType.AURA); - this.color.setWhite(true); - this.nightCard = true; - - // Enchant creature - TargetPermanent auraTarget = new TargetCreaturePermanent(); - this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - this.addAbility(new EnchantAbility(auraTarget)); - - // Enchanted creature has double strike. - this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( - DoubleStrikeAbility.getInstance(), AttachmentType.AURA - ))); - - // If Twinblade Invocation would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private TwinbladeInvocation(final TwinbladeInvocation card) { - super(card); - } - - @Override - public TwinbladeInvocation copy() { - return new TwinbladeInvocation(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java index 76c33e1b534..7ad5ef13c07 100644 --- a/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java +++ b/Mage.Sets/src/mage/cards/t/TwistsAndTurns.java @@ -3,19 +3,20 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.keyword.ExploreTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.GreenManaAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.Outcome; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; @@ -28,7 +29,7 @@ import java.util.UUID; /** * @author xenohedron */ -public final class TwistsAndTurns extends CardImpl { +public final class TwistsAndTurns extends TransformingDoubleFacedCard { private static final Condition condition = new PermanentsOnTheBattlefieldCondition( new FilterControlledLandPermanent("you control seven or more lands"), @@ -36,22 +37,36 @@ public final class TwistsAndTurns extends CardImpl { ); public TwistsAndTurns(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); - this.secondSideCardClazz = mage.cards.m.MycoidMaze.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{G}", + "Mycoid Maze", + new CardType[]{CardType.LAND}, new SubType[]{SubType.CAVE}, "" + ); + // Twists and Turns // If a creature you control would explore, instead you scry 1, then that creature explores. - this.addAbility(new SimpleStaticAbility(new TwistsAndTurnsReplacementEffect())); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new TwistsAndTurnsReplacementEffect())); // When Twists and Turns enters the battlefield, target creature you control explores. Ability ability = new EntersBattlefieldTriggeredAbility(new ExploreTargetEffect(false)); ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // When a land you control enters, if you control seven or more lands, transform Twists and Turns. - this.addAbility(new TransformAbility()); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + this.getLeftHalfCard().addAbility(new EntersBattlefieldControlledTriggeredAbility( new TransformSourceEffect(), StaticFilters.FILTER_LAND ).withInterveningIf(condition).setTriggerPhrase("When a land you control enters, ")); + + // Mycoid Maze + // {T}: Add {G}. + this.getRightHalfCard().addAbility(new GreenManaAbility()); + + // {3}{G}, {T}: Look at the top four cards of your library. You may reveal a creature card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. + Ability ability2 = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM + ), new ManaCostsImpl<>("{3}{G}")); + ability2.addCost(new TapSourceCost()); + this.getRightHalfCard().addAbility(ability2); } private TwistsAndTurns(final TwistsAndTurns card) { diff --git a/Mage.Sets/src/mage/cards/t/TyLeeArtfulAcrobat.java b/Mage.Sets/src/mage/cards/t/TyLeeArtfulAcrobat.java new file mode 100644 index 00000000000..2a70fc7b031 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TyLeeArtfulAcrobat.java @@ -0,0 +1,51 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.keyword.ProwessAbility; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TyLeeArtfulAcrobat extends CardImpl { + + public TyLeeArtfulAcrobat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PERFORMER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Prowess + this.addAbility(new ProwessAbility()); + + // Whenever Ty Lee attacks, you may pay {1}. When you do, target creature can't block this turn. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(new AttacksTriggeredAbility(new DoWhenCostPaid(ability, new GenericManaCost(1), "Pay {1}?"))); + } + + private TyLeeArtfulAcrobat(final TyLeeArtfulAcrobat card) { + super(card); + } + + @Override + public TyLeeArtfulAcrobat copy() { + return new TyLeeArtfulAcrobat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java b/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java new file mode 100644 index 00000000000..b2bc303ebe1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TyLeeChiBlocker.java @@ -0,0 +1,56 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ProwessAbility; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TyLeeChiBlocker extends CardImpl { + + public TyLeeChiBlocker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PERFORMER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Prowess + this.addAbility(new ProwessAbility()); + + // When Ty Lee enters, tap up to one target creature. It doesn't untap during its controller's untap step for as long as you control Ty Lee. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled, "it")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + } + + private TyLeeChiBlocker(final TyLeeChiBlocker card) { + super(card); + } + + @Override + public TyLeeChiBlocker copy() { + return new TyLeeChiBlocker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UlrichOfTheKrallenhorde.java b/Mage.Sets/src/mage/cards/u/UlrichOfTheKrallenhorde.java index 92b6bb25ea4..463cc3c97ae 100644 --- a/Mage.Sets/src/mage/cards/u/UlrichOfTheKrallenhorde.java +++ b/Mage.Sets/src/mage/cards/u/UlrichOfTheKrallenhorde.java @@ -1,16 +1,21 @@ package mage.cards.u; -import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.common.TransformsOrEntersTriggeredAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -18,28 +23,50 @@ import java.util.UUID; /** * @author fireshoes */ -public final class UlrichOfTheKrallenhorde extends CardImpl { +public final class UlrichOfTheKrallenhorde extends TransformingDoubleFacedCard { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("non-Werewolf creature you don't control"); + + static { + filter.add(Predicates.not(SubType.WEREWOLF.getPredicate())); + filter.add(TargetController.NOT_YOU.getControllerPredicate()); + } public UlrichOfTheKrallenhorde(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}{G}", + "Ulrich, Uncontested Alpha", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG" + ); - this.secondSideCardClazz = mage.cards.u.UlrichUncontestedAlpha.class; + // Ulrich of the Krallenhorde + this.getLeftHalfCard().setPT(4, 4); // Whenever this creature enters the battlefield or transforms into Ulrich of the Krallenhorde, target creature gets +4/+4 until end of turn. Ability ability = new TransformsOrEntersTriggeredAbility( new BoostTargetEffect(4, 4), false ); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // At the beginning of each upkeep, if no spells were cast last turn, transform Ulrich of the Krallenhorde. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Ulrich, Uncontested Alpha + this.getRightHalfCard().setPT(6, 6); + + // Whenever this creature transforms into Ulrich, Uncontested Alpha, you may have it fight target non-Werewolf creature you don't control. + Ability ability2 = new TransformIntoSourceTriggeredAbility( + new FightTargetSourceEffect() + .setText("you may have it fight target non-Werewolf creature you don't control"), + true, true + ); + ability2.addTarget(new TargetPermanent(filter)); + this.getRightHalfCard().addAbility(ability2); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ulrich, Uncontested Alpha. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private UlrichOfTheKrallenhorde(final UlrichOfTheKrallenhorde card) { diff --git a/Mage.Sets/src/mage/cards/u/UlrichUncontestedAlpha.java b/Mage.Sets/src/mage/cards/u/UlrichUncontestedAlpha.java deleted file mode 100644 index a900e313e68..00000000000 --- a/Mage.Sets/src/mage/cards/u/UlrichUncontestedAlpha.java +++ /dev/null @@ -1,66 +0,0 @@ -package mage.cards.u; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.FightTargetSourceEffect; -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.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.target.TargetPermanent; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class UlrichUncontestedAlpha extends CardImpl { - - private static final FilterCreaturePermanent filter - = new FilterCreaturePermanent("non-Werewolf creature you don't control"); - - static { - filter.add(Predicates.not(SubType.WEREWOLF.getPredicate())); - filter.add(TargetController.NOT_YOU.getControllerPredicate()); - } - - public UlrichUncontestedAlpha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setRed(true); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever this creature transforms into Ulrich, Uncontested Alpha, you may have it fight target non-Werewolf creature you don't control. - Ability ability = new TransformIntoSourceTriggeredAbility( - new FightTargetSourceEffect() - .setText("you may have it fight target non-Werewolf creature you don't control"), - true, true - ); - ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ulrich, Uncontested Alpha. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private UlrichUncontestedAlpha(final UlrichUncontestedAlpha card) { - super(card); - } - - @Override - public UlrichUncontestedAlpha copy() { - return new UlrichUncontestedAlpha(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UltimaOriginOfOblivion.java b/Mage.Sets/src/mage/cards/u/UltimaOriginOfOblivion.java index 54e0ab0e7d0..ee2cdcf61a6 100644 --- a/Mage.Sets/src/mage/cards/u/UltimaOriginOfOblivion.java +++ b/Mage.Sets/src/mage/cards/u/UltimaOriginOfOblivion.java @@ -84,7 +84,7 @@ class UltimaOriginOfOblivionEffect extends ContinuousEffectImpl { } switch (layer) { case TypeChangingEffects_4: - permanent.looseAllAbilities(game); + permanent.removeAllAbilities(source.getSourceId(), game); permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); return true; case AbilityAddingRemovingEffects_6: diff --git a/Mage.Sets/src/mage/cards/u/UltimeciaOmnipotent.java b/Mage.Sets/src/mage/cards/u/UltimeciaOmnipotent.java deleted file mode 100644 index db51fd3f13d..00000000000 --- a/Mage.Sets/src/mage/cards/u/UltimeciaOmnipotent.java +++ /dev/null @@ -1,48 +0,0 @@ -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; - -/** - * @author balazskristof - */ -public final class UltimeciaOmnipotent extends CardImpl { - - public UltimeciaOmnipotent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.NIGHTMARE); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - - this.color.setBlack(true); - this.color.setBlue(true); - - this.nightCard = true; - - // Menace - this.addAbility(new MenaceAbility()); - - // Time Compression -- When this creature transforms into Ultimecia, Omnipotent, take an extra turn after this one. - this.addAbility(new TransformIntoSourceTriggeredAbility(new AddExtraTurnControllerEffect()).withFlavorWord("Time Compression")); - } - - private UltimeciaOmnipotent(final UltimeciaOmnipotent card) { - super(card); - } - - @Override - public UltimeciaOmnipotent copy() { - return new UltimeciaOmnipotent(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UltimeciaTimeSorceress.java b/Mage.Sets/src/mage/cards/u/UltimeciaTimeSorceress.java index 539ac995609..31291e84299 100644 --- a/Mage.Sets/src/mage/cards/u/UltimeciaTimeSorceress.java +++ b/Mage.Sets/src/mage/cards/u/UltimeciaTimeSorceress.java @@ -1,44 +1,45 @@ package mage.cards.u; -import java.util.UUID; -import mage.MageInt; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.CompositeCost; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; import mage.abilities.effects.keyword.SurveilEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.MenaceAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author balazskristof */ -public final class UltimeciaTimeSorceress extends CardImpl { +public final class UltimeciaTimeSorceress extends TransformingDoubleFacedCard { public UltimeciaTimeSorceress(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WARLOCK); - this.power = new MageInt(4); - this.toughness = new MageInt(5); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WARLOCK}, "{3}{U}{B}", + "Ultimecia, Omnipotent", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.NIGHTMARE, SubType.WARLOCK}, "UB" + ); - this.secondSideCardClazz = mage.cards.u.UltimeciaOmnipotent.class; + // Ultimecia, Time Sorceress + this.getLeftHalfCard().setPT(4, 5); // Whenever Ultimecia enters or attacks, surveil 2. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new SurveilEffect(2))); + this.getLeftHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new SurveilEffect(2))); // At the beginning of your end step, you may pay {4}{U}{U}{B}{B} and exile eight cards from your graveyard. If you do, transform Ultimecia. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new DoIfCostPaid( + this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(new DoIfCostPaid( new TransformSourceEffect(), new CompositeCost( new ManaCostsImpl<>("{4}{U}{U}{B}{B}"), @@ -46,7 +47,15 @@ public final class UltimeciaTimeSorceress extends CardImpl { "{4}{U}{U}{B}{B} and exile eight cards from your graveyard" ) ))); - this.addAbility(new TransformAbility()); + + // Ultimecia, Omnipotent + this.getRightHalfCard().setPT(7, 7); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // Time Compression -- When this creature transforms into Ultimecia, Omnipotent, take an extra turn after this one. + this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new AddExtraTurnControllerEffect()).withFlavorWord("Time Compression")); } private UltimeciaTimeSorceress(final UltimeciaTimeSorceress card) { diff --git a/Mage.Sets/src/mage/cards/u/UltraMagnusArmoredCarrier.java b/Mage.Sets/src/mage/cards/u/UltraMagnusArmoredCarrier.java deleted file mode 100644 index 7e7d04bbe4b..00000000000 --- a/Mage.Sets/src/mage/cards/u/UltraMagnusArmoredCarrier.java +++ /dev/null @@ -1,87 +0,0 @@ -package mage.cards.u; - -import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LivingMetalAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -import mage.filter.common.FilterAttackingCreature; -import mage.game.Game; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class UltraMagnusArmoredCarrier extends CardImpl { - - public UltraMagnusArmoredCarrier(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(4); - this.toughness = new MageInt(7); - this.color.setRed(true); - this.color.setGreen(true); - this.color.setWhite(true); - this.nightCard = true; - - // Living metal - this.addAbility(new LivingMetalAbility()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Formidable -- Whenever Ultra Magnus attacks, attacking creatures you control gain indestructible until end of turn. If those creatures have total power 8 or greater, convert Ultra Magnus. - Ability ability = new AttacksTriggeredAbility(new GainAbilityControlledEffect( - IndestructibleAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_ATTACKING_CREATURES - )); - ability.addEffect(new ConditionalOneShotEffect( - new TransformSourceEffect(), UltraMagnusArmoredCarrierCondition.instance, - "If those creatures have total power 8 or greater, convert {this}" - )); - this.addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); - } - - private UltraMagnusArmoredCarrier(final UltraMagnusArmoredCarrier card) { - super(card); - } - - @Override - public UltraMagnusArmoredCarrier copy() { - return new UltraMagnusArmoredCarrier(this); - } -} - -enum UltraMagnusArmoredCarrierCondition implements Condition { - instance; - private static final FilterPermanent filter = new FilterAttackingCreature(); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - - @Override - public boolean apply(Game game, Ability source) { - return game - .getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source, game) - .stream() - .map(MageObject::getPower) - .mapToInt(MageInt::getValue) - .sum() >= 8; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/u/UltraMagnusTactician.java b/Mage.Sets/src/mage/cards/u/UltraMagnusTactician.java index 88775f8e8b6..e1fd4428dcd 100644 --- a/Mage.Sets/src/mage/cards/u/UltraMagnusTactician.java +++ b/Mage.Sets/src/mage/cards/u/UltraMagnusTactician.java @@ -1,20 +1,26 @@ package mage.cards.u; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; -import mage.abilities.keyword.WardAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.*; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; +import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -27,26 +33,46 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class UltraMagnusTactician extends CardImpl { +public final class UltraMagnusTactician extends TransformingDoubleFacedCard { public UltraMagnusTactician(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{R}{G}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{4}{R}{G}{W}", + "Ultra Magnus, Armored Carrier", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "RGW" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ROBOT); - this.power = new MageInt(7); - this.toughness = new MageInt(7); - - this.secondSideCardClazz = mage.cards.u.UltraMagnusArmoredCarrier.class; + // Ultra Magnus, Tactician + this.getLeftHalfCard().setPT(7, 7); // More Than Meets the Eye {2}{R}{G}{W} - this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{R}{G}{W}")); + this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{R}{G}{W}")); // Ward {2} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); + this.getLeftHalfCard().addAbility(new WardAbility(new ManaCostsImpl<>("{2}"), false)); // Whenever Ultra Magnus attacks, you may put an artifact creature card from your hand onto the battlefield tapped and attacking. If you do, convert Ultra Magnus at end of combat. - this.addAbility(new AttacksTriggeredAbility(new UltraMagnusTacticianEffect())); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new UltraMagnusTacticianEffect())); + + // Ultra Magnus, Armored Carrier + this.getRightHalfCard().setPT(4, 7); + + // Living metal + this.getRightHalfCard().addAbility(new LivingMetalAbility()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Formidable -- Whenever Ultra Magnus attacks, attacking creatures you control gain indestructible until end of turn. If those creatures have total power 8 or greater, convert Ultra Magnus. + Ability ability = new AttacksTriggeredAbility(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_ATTACKING_CREATURES + )); + ability.addEffect(new ConditionalOneShotEffect( + new TransformSourceEffect(), UltraMagnusArmoredCarrierCondition.instance, + "If those creatures have total power 8 or greater, convert {this}" + )); + this.getRightHalfCard().addAbility(ability.setAbilityWord(AbilityWord.FORMIDABLE)); } private UltraMagnusTactician(final UltraMagnusTactician card) { @@ -109,3 +135,23 @@ class UltraMagnusTacticianEffect extends OneShotEffect { return true; } } + +enum UltraMagnusArmoredCarrierCondition implements Condition { + instance; + private static final FilterPermanent filter = new FilterAttackingCreature(); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + @Override + public boolean apply(Game game, Ability source) { + return game + .getBattlefield() + .getActivePermanents(filter, source.getControllerId(), source, game) + .stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum() >= 8; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldAbomination.java b/Mage.Sets/src/mage/cards/u/UlvenwaldAbomination.java deleted file mode 100644 index 99ea3e10cc7..00000000000 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldAbomination.java +++ /dev/null @@ -1,43 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.Mana; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; - -/** - * - * @author fireshoes - */ -public final class UlvenwaldAbomination extends CardImpl { - - public UlvenwaldAbomination(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ELDRAZI); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(6); - - // this card is the second face of double-faced card - this.nightCard = true; - - // {T}: Add {C}{C}. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(2), new TapSourceCost())); - } - - private UlvenwaldAbomination(final UlvenwaldAbomination card) { - super(card); - } - - @Override - public UlvenwaldAbomination copy() { - return new UlvenwaldAbomination(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldBehemoth.java b/Mage.Sets/src/mage/cards/u/UlvenwaldBehemoth.java deleted file mode 100644 index 46d6434e6c9..00000000000 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldBehemoth.java +++ /dev/null @@ -1,63 +0,0 @@ -package mage.cards.u; - -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; -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.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class UlvenwaldBehemoth extends CardImpl { - - public UlvenwaldBehemoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.BEAST); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Haste - this.addAbility(HasteAbility.getInstance()); - - // Other creatures you control get +1/+1 and have trample and haste. - Ability ability = new SimpleStaticAbility(new BoostControlledEffect( - 1, 1, Duration.WhileOnBattlefield, true - )); - ability.addEffect(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE - ).setText("and have trample")); - ability.addEffect(new GainAbilityControlledEffect( - HasteAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE - ).setText("and haste")); - this.addAbility(ability); - } - - private UlvenwaldBehemoth(final UlvenwaldBehemoth card) { - super(card); - } - - @Override - public UlvenwaldBehemoth copy() { - return new UlvenwaldBehemoth(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldCaptive.java b/Mage.Sets/src/mage/cards/u/UlvenwaldCaptive.java index f8207fb0d22..302067464ca 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldCaptive.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldCaptive.java @@ -1,15 +1,15 @@ - package mage.cards.u; -import mage.MageInt; +import mage.Mana; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.GreenManaAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -19,26 +19,32 @@ import java.util.UUID; /** * @author fireshoes */ -public final class UlvenwaldCaptive extends CardImpl { +public final class UlvenwaldCaptive extends TransformingDoubleFacedCard { public UlvenwaldCaptive(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(1); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{1}{G}", + "Ulvenwald Abomination", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, "" + ); - this.secondSideCardClazz = mage.cards.u.UlvenwaldAbomination.class; + // Ulvenwald Captive + this.getLeftHalfCard().setPT(1, 2); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // {T}: Add {G}. - this.addAbility(new GreenManaAbility()); + this.getLeftHalfCard().addAbility(new GreenManaAbility()); // {5}{G}{G}: Transform Ulvenwald Captive. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}{G}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}{G}"))); + + // Ulvenwald Abomination + this.getRightHalfCard().setPT(4, 6); + + // {T}: Add {C}{C}. + this.getRightHalfCard().addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(2), new TapSourceCost())); } private UlvenwaldCaptive(final UlvenwaldCaptive card) { diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldMystics.java b/Mage.Sets/src/mage/cards/u/UlvenwaldMystics.java index cf32607f3d1..0f5fb24efb0 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldMystics.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldMystics.java @@ -1,10 +1,12 @@ package mage.cards.u; -import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,22 +15,29 @@ import java.util.UUID; /** * @author nantuko */ -public final class UlvenwaldMystics extends CardImpl { +public final class UlvenwaldMystics extends TransformingDoubleFacedCard { public UlvenwaldMystics(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.SHAMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{2}{G}{G}", + "Ulvenwald Primordials", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.u.UlvenwaldPrimordials.class; - - this.power = new MageInt(3); - this.toughness = new MageInt(3); + // Ulvenwald Mystics + this.getLeftHalfCard().setPT(3, 3); // At the beginning of each upkeep, if no spells were cast last turn, transform Ulvenwald Mystics. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Ulvenwald Primordials + this.getRightHalfCard().setPT(5, 5); + + // {G}: Regenerate Ulvenwald Primordials. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new ManaCostsImpl<>("{G}"))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ulvenwald Primordials. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private UlvenwaldMystics(final UlvenwaldMystics card) { diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldOddity.java b/Mage.Sets/src/mage/cards/u/UlvenwaldOddity.java index ae8c3820b74..ee54571f214 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldOddity.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldOddity.java @@ -1,43 +1,71 @@ 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.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 UlvenwaldOddity extends CardImpl { +public final class UlvenwaldOddity extends TransformingDoubleFacedCard { public UlvenwaldOddity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BEAST}, "{2}{G}{G}", + "Ulvenwald Behemoth", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BEAST, SubType.HORROR}, "G" + ); - this.subtype.add(SubType.BEAST); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.u.UlvenwaldBehemoth.class; + // Ulvenwald Oddity + this.getLeftHalfCard().setPT(4, 4); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // {5}{G}{G}: Transform Ulvenwald Oddity. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( new TransformSourceEffect(), new ManaCostsImpl<>("{5}{G}{G}") )); + + // Ulvenwald Behemoth + this.getRightHalfCard().setPT(8, 8); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Other creatures you control get +1/+1 and have trample and haste. + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, true + )); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + ).setText("and have trample")); + ability.addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + ).setText("and haste")); + this.getRightHalfCard().addAbility(ability); } private UlvenwaldOddity(final UlvenwaldOddity card) { diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldPrimordials.java b/Mage.Sets/src/mage/cards/u/UlvenwaldPrimordials.java deleted file mode 100644 index e74217697d3..00000000000 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldPrimordials.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.cards.u; - -import mage.MageInt; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.RegenerateSourceEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class UlvenwaldPrimordials extends CardImpl { - - public UlvenwaldPrimordials(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setGreen(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - // {G}: Regenerate Ulvenwald Primordials. - this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new ManaCostsImpl<>("{G}"))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ulvenwald Primordials. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private UlvenwaldPrimordials(final UlvenwaldPrimordials card) { - super(card); - } - - @Override - public UlvenwaldPrimordials copy() { - return new UlvenwaldPrimordials(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnagisSpray.java b/Mage.Sets/src/mage/cards/u/UnagisSpray.java new file mode 100644 index 00000000000..3cb20b02a75 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnagisSpray.java @@ -0,0 +1,63 @@ +package mage.cards.u; + +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnagisSpray extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(Predicates.or( + SubType.FISH.getPredicate(), + SubType.OCTOPUS.getPredicate(), + SubType.OTTER.getPredicate(), + SubType.SEAL.getPredicate(), + SubType.SERPENT.getPredicate(), + SubType.WHALE.getPredicate() + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a Fish, Octopus, Otter, Seal, Serpent, or Whale"); + + public UnagisSpray(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Target creature gets -4/-0 until end of turn. If you control a Fish, Octopus, Otter, Seal, Serpent, or Whale, draw a card. + this.getSpellAbility().addEffect(new BoostTargetEffect(-4, 0)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "If you control a Fish, Octopus, Otter, Seal, Serpent, or Whale, draw a card" + )); + this.getSpellAbility().addHint(hint); + } + + private UnagisSpray(final UnagisSpray card) { + super(card); + } + + @Override + public UnagisSpray copy() { + return new UnagisSpray(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UncleIroh.java b/Mage.Sets/src/mage/cards/u/UncleIroh.java new file mode 100644 index 00000000000..b4f17a16898 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UncleIroh.java @@ -0,0 +1,48 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.keyword.FirebendingAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UncleIroh extends CardImpl { + + private static final FilterCard filter = new FilterCard(SubType.LESSON, "Lesson spells"); + + public UncleIroh(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R/G}{R/G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // Lesson spells you cast cost {1} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); + } + + private UncleIroh(final UncleIroh card) { + super(card); + } + + @Override + public UncleIroh copy() { + return new UncleIroh(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnclesMusings.java b/Mage.Sets/src/mage/cards/u/UnclesMusings.java new file mode 100644 index 00000000000..644782180ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnclesMusings.java @@ -0,0 +1,44 @@ +package mage.cards.u; + +import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetsCountAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnclesMusings extends CardImpl { + + public UnclesMusings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}{G}"); + + // Converge -- Return up to X permanent cards from your graveyard to your hand, where X is the number of colors of mana spent to cast this spell. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect() + .setText("return up to X permanent cards from your graveyard to your hand, " + + "where X is the number of colors of mana spent to cast this spell")); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_PERMANENT)); + this.getSpellAbility().setTargetAdjuster(new TargetsCountAdjuster(ColorsOfManaSpentToCastCount.getInstance())); + this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE); + + // Exile Uncle's Musings. + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); + } + + private UnclesMusings(final UnclesMusings card) { + super(card); + } + + @Override + public UnclesMusings copy() { + return new UnclesMusings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderwaterTunnelSlimyAquarium.java b/Mage.Sets/src/mage/cards/u/UnderwaterTunnelSlimyAquarium.java new file mode 100644 index 00000000000..93331c50117 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnderwaterTunnelSlimyAquarium.java @@ -0,0 +1,37 @@ +package mage.cards.u; + +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.keyword.ManifestDreadEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnderwaterTunnelSlimyAquarium extends RoomCard { + + public UnderwaterTunnelSlimyAquarium(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{U}", "{3}{U}"); + + // Underwater Tunnel + // When you unlock this door, surveil 2. + this.getLeftHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new SurveilEffect(2), false, true)); + + // Slimy Aquarium + // When you unlock this door, manifest dread, then put a +1/+1 counter on that creature. + this.getRightHalfCard().addAbility(new UnlockThisDoorTriggeredAbility(new ManifestDreadEffect(CounterType.P1P1.createInstance()), false, false)); + } + + private UnderwaterTunnelSlimyAquarium(final UnderwaterTunnelSlimyAquarium card) { + super(card); + } + + @Override + public UnderwaterTunnelSlimyAquarium copy() { + return new UnderwaterTunnelSlimyAquarium(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java index 6fec7feb0c5..2f34acedc29 100644 --- a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java +++ b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java @@ -18,7 +18,7 @@ public final class UnderworldDreams extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{B}{B}"); // Whenever an opponent draws a card, Underworld Dreams deals 1 damage to that player. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that player"), false, true)); } private UnderworldDreams(final UnderworldDreams card) { diff --git a/Mage.Sets/src/mage/cards/u/UnexpectedAssistance.java b/Mage.Sets/src/mage/cards/u/UnexpectedAssistance.java new file mode 100644 index 00000000000..07614b9e66d --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnexpectedAssistance.java @@ -0,0 +1,34 @@ +package mage.cards.u; + +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnexpectedAssistance extends CardImpl { + + public UnexpectedAssistance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // Draw three cards, then discard a card. + this.getSpellAbility().addEffect(new DrawDiscardControllerEffect(3, 1)); + } + + private UnexpectedAssistance(final UnexpectedAssistance card) { + super(card); + } + + @Override + public UnexpectedAssistance copy() { + return new UnexpectedAssistance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnhallowedCathar.java b/Mage.Sets/src/mage/cards/u/UnhallowedCathar.java deleted file mode 100644 index 9f61fbec892..00000000000 --- a/Mage.Sets/src/mage/cards/u/UnhallowedCathar.java +++ /dev/null @@ -1,42 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.common.CantBlockAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author BetaSteward - */ -public final class UnhallowedCathar extends CardImpl { - - public UnhallowedCathar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.ZOMBIE); - this.subtype.add(SubType.SOLDIER); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(2); - this.toughness = new MageInt(1); - - // Unhallowed Cathar can't block. - this.addAbility(new CantBlockAbility()); - } - - private UnhallowedCathar(final UnhallowedCathar card) { - super(card); - } - - @Override - public UnhallowedCathar copy() { - return new UnhallowedCathar(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java b/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java new file mode 100644 index 00000000000..4cabd2ee8de --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnholyAnnexRitualChamber.java @@ -0,0 +1,90 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.permanent.token.Demon66Token; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class UnholyAnnexRitualChamber extends RoomCard { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Demon"); + + static { + filter.add(SubType.DEMON.getPredicate()); + } + + public UnholyAnnexRitualChamber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{B}", "{3}{B}{B}"); + this.subtype.add(SubType.ROOM); + + // Unholy Annex: At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life. + Ability left = new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1)); + left.addEffect(new ConditionalOneShotEffect( + new UnholyAnnexDrainEffect(), new LoseLifeSourceControllerEffect(2), + new PermanentsOnTheBattlefieldCondition(filter), "If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life" + )); + left.addHint(new ConditionHint(new PermanentsOnTheBattlefieldCondition(filter), "You control a Demon")); + this.getLeftHalfCard().addAbility(left); + + // Ritual Chamber: When you unlock this door, create a 6/6 black Demon creature token with flying. + Ability right = new UnlockThisDoorTriggeredAbility(new CreateTokenEffect(new Demon66Token()), false, false); + this.getRightHalfCard().addAbility(right); + } + + private UnholyAnnexRitualChamber(final UnholyAnnexRitualChamber card) { + super(card); + } + + @Override + public UnholyAnnexRitualChamber copy() { + return new UnholyAnnexRitualChamber(this); + } +} + +class UnholyAnnexDrainEffect extends OneShotEffect { + + UnholyAnnexDrainEffect() { + super(Outcome.GainLife); + this.staticText = "each opponent loses 2 life and you gain 2 life"; + } + + private UnholyAnnexDrainEffect(final UnholyAnnexDrainEffect effect) { + super(effect); + } + + @Override + public UnholyAnnexDrainEffect copy() { + return new UnholyAnnexDrainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(opponentId); + if (player != null) { + player.loseLife(2, game, source, false); + } + } + game.getPlayer(source.getControllerId()).gainLife(2, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnholyFiend.java b/Mage.Sets/src/mage/cards/u/UnholyFiend.java deleted file mode 100644 index 726ca0db1bb..00000000000 --- a/Mage.Sets/src/mage/cards/u/UnholyFiend.java +++ /dev/null @@ -1,41 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author Loki - */ -public final class UnholyFiend extends CardImpl { - - public UnholyFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.HORROR); - - this.color.setBlack(true); - - this.power = new MageInt(3); - this.toughness = new MageInt(3); - - this.nightCard = true; - - this.addAbility(new BeginningOfEndStepTriggeredAbility(new LoseLifeSourceControllerEffect(1))); - } - - private UnholyFiend(final UnholyFiend card) { - super(card); - } - - @Override - public UnholyFiend copy() { - return new UnholyFiend(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java b/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java deleted file mode 100644 index 71bf6341fa8..00000000000 --- a/Mage.Sets/src/mage/cards/u/UnimpededTrespasser.java +++ /dev/null @@ -1,40 +0,0 @@ - -package mage.cards.u; - -import java.util.UUID; -import mage.MageInt; -import mage.abilities.keyword.CantBeBlockedSourceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author fireshoes - */ -public final class UnimpededTrespasser extends CardImpl { - - public UnimpededTrespasser(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},""); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.color.setBlue(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Unimpeded Trespasser can't be blocked. - this.addAbility(new CantBeBlockedSourceAbility()); - } - - private UnimpededTrespasser(final UnimpededTrespasser card) { - super(card); - } - - @Override - public UnimpededTrespasser copy() { - return new UnimpededTrespasser(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UninvitedGeist.java b/Mage.Sets/src/mage/cards/u/UninvitedGeist.java index 4f142aba650..d3a58adfc90 100644 --- a/Mage.Sets/src/mage/cards/u/UninvitedGeist.java +++ b/Mage.Sets/src/mage/cards/u/UninvitedGeist.java @@ -1,13 +1,12 @@ package mage.cards.u; -import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; import mage.abilities.keyword.SkulkAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -16,23 +15,27 @@ import java.util.UUID; /** * @author fireshoes */ -public final class UninvitedGeist extends CardImpl { +public final class UninvitedGeist extends TransformingDoubleFacedCard { public UninvitedGeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{U}", + "Unimpeded Trespasser", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"); - this.secondSideCardClazz = mage.cards.u.UnimpededTrespasser.class; + this.getLeftHalfCard().setPT(2, 2); + this.getRightHalfCard().setPT(3, 3); // Skulk (This creature can't be blocked by creatures with greater power.) - this.addAbility(new SkulkAbility()); + this.getLeftHalfCard().addAbility(new SkulkAbility()); // When Uninvited Geist deals combat damage to a player, transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false)); + this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false)); + // Unimpeded Trespasser + + // Unimpeded Trespasser can't be blocked. + this.getRightHalfCard().addAbility(new CantBeBlockedSourceAbility()); } private UninvitedGeist(final UninvitedGeist card) { diff --git a/Mage.Sets/src/mage/cards/u/UnitedFront.java b/Mage.Sets/src/mage/cards/u/UnitedFront.java new file mode 100644 index 00000000000..11f63311ba4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnitedFront.java @@ -0,0 +1,38 @@ +package mage.cards.u; + +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.AllyToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnitedFront extends CardImpl { + + public UnitedFront(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{W}{W}"); + + // Create X 1/1 white Ally creature tokens, then put a +1/+1 counter on each creature you control. + this.getSpellAbility().addEffect(new CreateTokenEffect(new AllyToken(), GetXValue.instance)); + this.getSpellAbility().addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ).concatBy(", then")); + } + + private UnitedFront(final UnitedFront card) { + super(card); + } + + @Override + public UnitedFront copy() { + return new UnitedFront(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnleashShell.java b/Mage.Sets/src/mage/cards/u/UnleashShell.java index a52d7e657df..ffd4fd4c34d 100644 --- a/Mage.Sets/src/mage/cards/u/UnleashShell.java +++ b/Mage.Sets/src/mage/cards/u/UnleashShell.java @@ -1,14 +1,13 @@ package mage.cards.u; -import java.util.UUID; - -import mage.abilities.effects.common.DamageTargetControllerEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreatureOrPlaneswalker; +import java.util.UUID; + /** * * @author weirddan455 @@ -19,9 +18,8 @@ public final class UnleashShell extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}{R}"); // Unleash Shell deals 5 damage to target creature or planeswalker and 2 damage to that permanent's controller. - this.getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellAbility().addEffect(new DamageTargetControllerEffect(2).setText("and 2 damage to that permanent's controller")); this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addEffect(new DamageTargetAndTargetControllerEffect(5, 2)); } private UnleashShell(final UnleashShell card) { diff --git a/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java b/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java new file mode 100644 index 00000000000..37d0e1f4564 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnluckyCabbageMerchant.java @@ -0,0 +1,92 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +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.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.FoodToken; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnluckyCabbageMerchant extends CardImpl { + + public UnluckyCabbageMerchant(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); + + // When this creature enters, create a Food token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); + + // Whenever you sacrifice a Food, you may search your library for a basic land card and put it onto the battlefield tapped. If you search your library this way, put this creature on the bottom of its owner's library, then shuffle. + this.addAbility(new SacrificePermanentTriggeredAbility( + new UnluckyCabbageMerchantEffect(), StaticFilters.FILTER_CONTROLLED_FOOD + )); + } + + private UnluckyCabbageMerchant(final UnluckyCabbageMerchant card) { + super(card); + } + + @Override + public UnluckyCabbageMerchant copy() { + return new UnluckyCabbageMerchant(this); + } +} + +class UnluckyCabbageMerchantEffect extends OneShotEffect { + + UnluckyCabbageMerchantEffect() { + super(Outcome.Benefit); + staticText = "you may search your library for a basic land card and put it onto the battlefield tapped. " + + "If you search your library this way, put this creature on the bottom of its owner's library, then shuffle"; + } + + private UnluckyCabbageMerchantEffect(final UnluckyCabbageMerchantEffect effect) { + super(effect); + } + + @Override + public UnluckyCabbageMerchantEffect copy() { + return new UnluckyCabbageMerchantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.chooseUse( + Outcome.PutLandInPlay, "Search your library for a basic land?", source, game + )) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); + if (!player.searchLibrary(target, source, game)) { + return false; + } + player.moveCards( + player.getLibrary().getCard(target.getFirstTarget(), game), Zone.BATTLEFIELD, + source, game, true, false, false, null + ); + player.putCardsOnBottomOfLibrary(source.getSourcePermanentIfItStillExists(game), game, source); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnsealTheNecropolis.java b/Mage.Sets/src/mage/cards/u/UnsealTheNecropolis.java index 90a77b78772..7f6dd20c4a3 100644 --- a/Mage.Sets/src/mage/cards/u/UnsealTheNecropolis.java +++ b/Mage.Sets/src/mage/cards/u/UnsealTheNecropolis.java @@ -1,20 +1,13 @@ package mage.cards.u; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.OneShotNonTargetEffect; import mage.abilities.effects.common.MillCardsEachPlayerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; 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.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -29,7 +22,8 @@ public final class UnsealTheNecropolis extends CardImpl { // Each player mills three cards. Then you return up to two creature cards from your graveyard to your hand. this.getSpellAbility().addEffect(new MillCardsEachPlayerEffect(3, TargetController.EACH_PLAYER)); - this.getSpellAbility().addEffect(new UnsealTheNecropolisEffect()); + this.getSpellAbility().addEffect(new OneShotNonTargetEffect(new ReturnFromGraveyardToHandTargetEffect().setText("Then you return up to two creature cards from your graveyard to your hand"), + new TargetCardInYourGraveyard(0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true))); } private UnsealTheNecropolis(final UnsealTheNecropolis card) { @@ -41,34 +35,3 @@ public final class UnsealTheNecropolis extends CardImpl { return new UnsealTheNecropolis(this); } } - -class UnsealTheNecropolisEffect extends OneShotEffect { - - UnsealTheNecropolisEffect() { - super(Outcome.Benefit); - staticText = "Then you return up to two creature cards from your graveyard to your hand"; - } - - private UnsealTheNecropolisEffect(final UnsealTheNecropolisEffect effect) { - super(effect); - } - - @Override - public UnsealTheNecropolisEffect copy() { - return new UnsealTheNecropolisEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCard target = new TargetCardInYourGraveyard( - 0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true - ); - player.choose(outcome, target, source, game); - Cards cards = new CardsImpl(target.getTargets()); - return !cards.isEmpty() && player.moveCards(cards, Zone.HAND, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java b/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java index 2115fe4af1a..aab3f9d2138 100644 --- a/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java +++ b/Mage.Sets/src/mage/cards/u/UnstableGlyphbridge.java @@ -2,42 +2,73 @@ package mage.cards.u; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; 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.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.filter.FilterSpell; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import mage.watchers.common.PlayersAttackedThisTurnWatcher; import java.util.UUID; /** * @author notgreat */ -public final class UnstableGlyphbridge extends CardImpl { +public final class UnstableGlyphbridge extends TransformingDoubleFacedCard { + + private static final FilterSpell filter = new FilterSpell("a spell during their turn"); + + static { + filter.add(TargetController.ACTIVE.getControllerPredicate()); + } public UnstableGlyphbridge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{W}{W}"); - this.secondSideCardClazz = mage.cards.s.SandswirlWanderglyph.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{3}{W}{W}", + "Sandswirl Wanderglyph", + new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.GOLEM}, "W" + ); + // Unstable Glyphbridge // When Unstable Glyphbridge enters the battlefield, if you cast it, for each player, choose a creature with power 2 or less that player controls. Then destroy all creatures except creatures chosen this way. - this.addAbility(new EntersBattlefieldTriggeredAbility(new UnstableGlyphbridgeEffect()) + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new UnstableGlyphbridgeEffect()) .withInterveningIf(CastFromEverywhereSourceCondition.instance)); // Craft with artifact {3}{W}{W} - this.addAbility(new CraftAbility("{3}{W}{W}")); + this.getLeftHalfCard().addAbility(new CraftAbility("{3}{W}{W}")); + + // Sandswirl Wanderglyph + this.getRightHalfCard().setPT(5, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Whenever an opponent casts a spell during their turn, they can't attack you or planeswalkers you control this turn. + this.getRightHalfCard().addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, + new CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(), filter, false, SetTargetPointer.PLAYER)); + + // Each opponent who attacked you or a planeswalker you control this turn can't cast spells. + Ability ability = new SimpleStaticAbility(new SandswirlWanderglyphCantCastEffect()); + ability.addWatcher(new PlayersAttackedThisTurnWatcher()); + this.getRightHalfCard().addAbility(ability); } private UnstableGlyphbridge(final UnstableGlyphbridge card) { @@ -97,3 +128,68 @@ class UnstableGlyphbridgeEffect extends OneShotEffect { return true; } } + +class SandswirlWanderglyphCantCastEffect extends ContinuousRuleModifyingEffectImpl { + + SandswirlWanderglyphCantCastEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Each opponent who attacked you or a planeswalker you control this turn can't cast spells"; + } + + private SandswirlWanderglyphCantCastEffect(final SandswirlWanderglyphCantCastEffect effect) { + super(effect); + } + + @Override + public SandswirlWanderglyphCantCastEffect copy() { + return new SandswirlWanderglyphCantCastEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (game.isActivePlayer(event.getPlayerId()) && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + PlayersAttackedThisTurnWatcher watcher = game.getState().getWatcher(PlayersAttackedThisTurnWatcher.class); + return watcher != null && watcher.hasPlayerAttackedPlayerOrControlledPlaneswalker(event.getPlayerId(), source.getControllerId()); + } + return false; + } + +} + +class CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect extends RestrictionEffect { + CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect() { + super(Duration.EndOfTurn); + staticText = "they can't attack you or planeswalkers you control this turn"; + } + + private CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(final CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect effect) { + super(effect); + } + + @Override + public CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect copy() { + return new CantAttackSourcePlayerOrPlaneswalkerThisTurnEffect(this); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (game.getPlayer(defenderId) != null) { + return !(source.getControllerId().equals(defenderId)); + } + Permanent defender = game.getPermanent(defenderId); + if (defender != null && defender.isPlaneswalker()) { + return !(source.getControllerId().equals(defender.getControllerId())); + } + return true; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getControllerId().equals(getTargetPointer().getFirst(game, source)); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UntamedPup.java b/Mage.Sets/src/mage/cards/u/UntamedPup.java deleted file mode 100644 index 4dbcd4007c9..00000000000 --- a/Mage.Sets/src/mage/cards/u/UntamedPup.java +++ /dev/null @@ -1,74 +0,0 @@ -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.mana.ManaCostsImpl; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.keyword.NightboundAbility; -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.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.target.common.TargetCreaturePermanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class UntamedPup extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("Wolves and Werewolves"); - - static { - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public UntamedPup(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.color.setGreen(true); - this.nightCard = true; - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Other Wolves and Werewolves you control have trample. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true - ))); - - // {3}{G}: Put a +1/+1 counter on target creature. - Ability ability = new SimpleActivatedAbility( - new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{3}{G}") - ); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private UntamedPup(final UntamedPup card) { - super(card); - } - - @Override - public UntamedPup copy() { - return new UntamedPup(this); - } -} diff --git a/Mage.Sets/src/mage/cards/u/Urabrask.java b/Mage.Sets/src/mage/cards/u/Urabrask.java index 899f4552ec6..b3a97c37229 100644 --- a/Mage.Sets/src/mage/cards/u/Urabrask.java +++ b/Mage.Sets/src/mage/cards/u/Urabrask.java @@ -1,23 +1,34 @@ package mage.cards.u; -import mage.MageInt; import mage.Mana; import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SagaAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.cards.Card; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; 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.game.permanent.token.TreasureToken; +import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.watchers.common.CastFromGraveyardWatcher; import mage.watchers.common.SpellsCastWatcher; import java.util.Objects; @@ -26,20 +37,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class Urabrask extends CardImpl { +public final class Urabrask extends TransformingDoubleFacedCard { public Urabrask(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{2}{R}{R}", + "The Great Work", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "R" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.PRAETOR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.t.TheGreatWork.class; + // Urabrask + this.getLeftHalfCard().setPT(4, 4); // First strike - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // Whenever you cast an instant or sorcery spell, Urabrask deals 1 damage to target opponent. Add {R}. Ability ability = new SpellCastControllerTriggeredAbility( @@ -47,14 +58,37 @@ public final class Urabrask extends CardImpl { ); ability.addEffect(new BasicManaEffect(Mana.RedMana(1))); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {R}: Exile Urabrask, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery and only if you've cast three or more instant and/or sorcery spells this turn. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateIfConditionActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{R}"), UrabraskCondition.instance ).setTiming(TimingRule.SORCERY)); + + // The Great Work + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- The Great Work deals 3 damage to target opponent and each creature they control. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + new TheGreatWorkEffect(), new TargetOpponent() + ); + + // II -- Create three Treasure tokens. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_II, + new CreateTokenEffect(new TreasureToken(), 3) + ); + + // III -- Until end of turn, you may cast instant and sorcery spells from any graveyard. If a spell cast this way would be put into a graveyard, exile it instead. Exile The Great Work, then return it to the battlefield. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, new TheGreatWorkCastFromGraveyardEffect(), + new TheGreatWorkReplacementEffect(), new ExileSourceAndReturnFaceUpEffect() + ); + sagaAbility.addWatcher(new CastFromGraveyardWatcher()); + this.getRightHalfCard().addAbility(sagaAbility); } private Urabrask(final Urabrask card) { @@ -87,3 +121,120 @@ enum UrabraskCondition implements Condition { return "if you've cast three or more instant and/or sorcery spells this turn"; } } + +class TheGreatWorkEffect extends OneShotEffect { + + TheGreatWorkEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 3 damage to target opponent and each creature they control"; + } + + private TheGreatWorkEffect(final TheGreatWorkEffect effect) { + super(effect); + } + + @Override + public TheGreatWorkEffect copy() { + return new TheGreatWorkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + player.damage(3, source, game); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game + )) { + permanent.damage(3, source, game); + } + return true; + } +} + +class TheGreatWorkCastFromGraveyardEffect extends AsThoughEffectImpl { + + TheGreatWorkCastFromGraveyardEffect() { + super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + staticText = "until end of turn, you may cast instant and sorcery spells from any graveyard"; + } + + private TheGreatWorkCastFromGraveyardEffect(final TheGreatWorkCastFromGraveyardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public TheGreatWorkCastFromGraveyardEffect copy() { + return new TheGreatWorkCastFromGraveyardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Card card = game.getCard(objectId); + if (card != null + && affectedControllerId.equals(source.getControllerId()) + && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game) + && Zone.GRAVEYARD.equals(game.getState().getZone(card.getId()))) { + game.getState().setValue("TheGreatWork", card); + return true; + } + return false; + } +} + +class TheGreatWorkReplacementEffect extends ReplacementEffectImpl { + + TheGreatWorkReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Exile); + staticText = "if a spell cast this way would be put into a graveyard, exile it instead"; + } + + private TheGreatWorkReplacementEffect(final TheGreatWorkReplacementEffect effect) { + super(effect); + } + + @Override + public TheGreatWorkReplacementEffect copy() { + return new TheGreatWorkReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Card card = (Card) game.getState().getValue("TheGreatWork"); + if (card != null) { + ((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) { + if (Zone.GRAVEYARD != ((ZoneChangeEvent) event).getToZone()) { + return false; + } + Card card = game.getCard(event.getSourceId()); + if (card == null || (!card.isInstant(game) && !card.isSorcery(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/u/UrbanRetreat.java b/Mage.Sets/src/mage/cards/u/UrbanRetreat.java index f47fcec2a02..d24fb23966c 100644 --- a/Mage.Sets/src/mage/cards/u/UrbanRetreat.java +++ b/Mage.Sets/src/mage/cards/u/UrbanRetreat.java @@ -48,7 +48,7 @@ public final class UrbanRetreat extends CardImpl { // {2}, Return a tapped creature you control to its owner's hand: Put this card from your hand onto the battlefield. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.HAND, new UrbanRetreatEffect(), new GenericManaCost(2)); - ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent())); + ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UrborgStalker.java b/Mage.Sets/src/mage/cards/u/UrborgStalker.java index e8550aaf34a..d96e751b782 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgStalker.java +++ b/Mage.Sets/src/mage/cards/u/UrborgStalker.java @@ -41,7 +41,7 @@ public final class UrborgStalker extends CardImpl { // At the beginning of each player's upkeep, if that player controls a nonblack, nonland permanent, Urborg Stalker deals 1 damage to that player. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - TargetController.EACH_PLAYER, new DamageTargetEffect(1, true, "that player"), false + TargetController.EACH_PLAYER, new DamageTargetEffect(1).withTargetDescription("that player"), false ).withInterveningIf(condition)); } diff --git a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java index 0b091865b6b..c720f977813 100644 --- a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java +++ b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java @@ -190,7 +190,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect { break; case 12: // NISSA SAGE ANIMIST 1 sb.append("Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand."); - effects.add(new mage.cards.n.NissaSageAnimist(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + effects.add(new mage.cards.n.NissaVastwoodSeer(controller.getId(), setInfo).getRightHalfCard().getAbilities().get(2).getEffects().get(0)); break; case 13: // NISSA WORLDWAKER 1 sb.append("Target land you control becomes a 4/4 Elemental creature with trample. It's still a land."); diff --git a/Mage.Sets/src/mage/cards/u/UrzasRage.java b/Mage.Sets/src/mage/cards/u/UrzasRage.java index cd87a10bf6e..acb769b082b 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasRage.java +++ b/Mage.Sets/src/mage/cards/u/UrzasRage.java @@ -28,7 +28,7 @@ public final class UrzasRage extends CardImpl { // Urza's Rage deals 3 damage to any target. If Urza's Rage was kicked, instead it deals 10 damage to that creature or player and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(10, false), new DamageTargetEffect(3), + new DamageTargetEffect(10).withCantBePrevented(), new DamageTargetEffect(3), KickedCondition.ONCE, "{this} deals 3 damage to any target. If this spell was kicked, " + "instead it deals 10 damage to that permanent or player and the damage can't be prevented." )); diff --git a/Mage.Sets/src/mage/cards/v/ValorsReachTagTeam.java b/Mage.Sets/src/mage/cards/v/ValorsReachTagTeam.java deleted file mode 100644 index b01d199a7c8..00000000000 --- a/Mage.Sets/src/mage/cards/v/ValorsReachTagTeam.java +++ /dev/null @@ -1,35 +0,0 @@ -package mage.cards.v; - -import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.game.permanent.token.ValorsReachTagTeamToken; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ValorsReachTagTeam extends CardImpl { - - public ValorsReachTagTeam(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); - - this.color.setWhite(true); - this.color.setRed(true); - this.nightCard = true; - - // Create two 3/2 red and white Warrior creature tokens with "Whenever this creature and at least one other creature token attack, put a +1/+1 counter on this creature." - this.getSpellAbility().addEffect(new CreateTokenEffect(new ValorsReachTagTeamToken(), 2)); - } - - private ValorsReachTagTeam(final ValorsReachTagTeam card) { - super(card); - } - - @Override - public ValorsReachTagTeam copy() { - return new ValorsReachTagTeam(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java b/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java index 481660bf8b7..1647c56c58f 100644 --- a/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java +++ b/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java @@ -1,19 +1,23 @@ - package mage.cards.v; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +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.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.mana.RedManaAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.common.TargetAnyTarget; import mage.util.CardUtil; import mage.watchers.common.CastSpellLastTurnWatcher; @@ -22,20 +26,31 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class VancesBlastingCannons extends CardImpl { +public final class VancesBlastingCannons extends TransformingDoubleFacedCard { public VancesBlastingCannons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); - - this.supertype.add(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.s.SpitfireBastion.class; + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{3}{R}", + "Spitfire Bastion", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Vance's Blasting Cannons // At the beginning of your upkeep, exile the top card of your library. If it's a nonland card, you may cast that card this turn. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new VancesBlastingCannonsExileEffect())); + this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new VancesBlastingCannonsExileEffect())); // Whenever you cast your third spell in a turn, transform Vance's Blasting Cannons. - this.addAbility(new TransformAbility()); - this.addAbility(new VancesBlastingCannonsTriggeredAbility()); + this.getLeftHalfCard().addAbility(new VancesBlastingCannonsTriggeredAbility()); + + // Spitfire Bastion + // {T}: Add {R}. + this.getRightHalfCard().addAbility(new RedManaAbility()); + + // {2}{R}, {T}: Spitfire Bastion deals 3 damage to any target. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3), new TapSourceCost()); + ability.addCost(new ManaCostsImpl<>("{2}{R}")); + ability.addTarget(new TargetAnyTarget()); + this.getRightHalfCard().addAbility(ability); } private VancesBlastingCannons(final VancesBlastingCannons card) { diff --git a/Mage.Sets/src/mage/cards/v/VaultOfCatlacan.java b/Mage.Sets/src/mage/cards/v/VaultOfCatlacan.java deleted file mode 100644 index 97dcd4e08c2..00000000000 --- a/Mage.Sets/src/mage/cards/v/VaultOfCatlacan.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.v; - -import mage.Mana; -import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.effects.mana.DynamicManaEffect; -import mage.abilities.hint.common.ArtifactYouControlHint; -import mage.abilities.mana.AnyColorManaAbility; -import mage.abilities.mana.SimpleManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SuperType; -import mage.constants.Zone; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class VaultOfCatlacan extends CardImpl { - - public VaultOfCatlacan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.nightCard = true; - - // (Transforms from Storm the Vault.) - - // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - - // {T}: Add {U} for each artifact you control. - this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, - new DynamicManaEffect(Mana.BlueMana(1), ArtifactYouControlCount.instance), - new TapSourceCost()) - .addHint(ArtifactYouControlHint.instance)); - - } - - private VaultOfCatlacan(final VaultOfCatlacan card) { - super(card); - } - - @Override - public VaultOfCatlacan copy() { - return new VaultOfCatlacan(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VectorGlider.java b/Mage.Sets/src/mage/cards/v/VectorGlider.java deleted file mode 100644 index bab0f279c24..00000000000 --- a/Mage.Sets/src/mage/cards/v/VectorGlider.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -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 VectorGlider extends CardImpl { - - public VectorGlider(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - } - - private VectorGlider(final VectorGlider card) { - super(card); - } - - @Override - public VectorGlider copy() { - return new VectorGlider(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VenatHeartOfHydaelyn.java b/Mage.Sets/src/mage/cards/v/VenatHeartOfHydaelyn.java index 217d13738c9..f7d7e9b394f 100644 --- a/Mage.Sets/src/mage/cards/v/VenatHeartOfHydaelyn.java +++ b/Mage.Sets/src/mage/cards/v/VenatHeartOfHydaelyn.java @@ -1,29 +1,36 @@ package mage.cards.v; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; +import mage.counters.CounterType; import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.game.Controllable; +import mage.game.Game; +import mage.target.TargetPermanent; import mage.target.common.TargetNonlandPermanent; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class VenatHeartOfHydaelyn extends CardImpl { +public final class VenatHeartOfHydaelyn extends TransformingDoubleFacedCard { private static final FilterSpell filter = new FilterSpell("a legendary spell"); @@ -32,27 +39,41 @@ public final class VenatHeartOfHydaelyn extends CardImpl { } public VenatHeartOfHydaelyn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDER, SubType.WIZARD}, "{1}{W}{W}", + "Hydaelyn, the Mothercrystal", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.GOD}, "W" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ELDER); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.h.HydaelynTheMothercrystal.class; + // Venat, Heart of Hydaelyn + this.getLeftHalfCard().setPT(3, 3); // Whenever you cast a legendary spell, draw a card. This ability triggers only once each turn. - this.addAbility(new SpellCastControllerTriggeredAbility( + this.getLeftHalfCard().addAbility(new SpellCastControllerTriggeredAbility( new DrawCardSourceControllerEffect(1), filter, false ).setTriggersLimitEachTurn(1)); // Hero's Sundering -- {7}, {T}: Exile target nonland permanent. Transform Venat. Activate only as a sorcery. - this.addAbility(new TransformAbility()); Ability ability = new ActivateAsSorceryActivatedAbility(new ExileTargetEffect(), new GenericManaCost(7)); ability.addCost(new TapSourceCost()); ability.addEffect(new TransformSourceEffect()); ability.addTarget(new TargetNonlandPermanent()); - this.addAbility(ability.withFlavorWord("Hero's Sundering")); + this.getLeftHalfCard().addAbility(ability.withFlavorWord("Hero's Sundering")); + + // Hydaelyn, the Mothercrystal + this.getRightHalfCard().setPT(4, 4); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Blessing of Light -- At the beginning of combat on your turn, put a +1/+1 counter on another target creature you control. Until your next turn, it gains indestructible. If that creature is legendary, draw a card. + Ability ability2 = new BeginningOfCombatTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability2.addEffect(new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("Until your next turn, it gains indestructible")); + ability2.addEffect(new HydaelynTheMothercrystalEffect()); + ability2.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); + this.getRightHalfCard().addAbility(ability2.withFlavorWord("Blessing of Light")); } private VenatHeartOfHydaelyn(final VenatHeartOfHydaelyn card) { @@ -64,3 +85,34 @@ public final class VenatHeartOfHydaelyn extends CardImpl { return new VenatHeartOfHydaelyn(this); } } + +class HydaelynTheMothercrystalEffect extends OneShotEffect { + + HydaelynTheMothercrystalEffect() { + super(Outcome.Benefit); + staticText = "If that creature is legendary, draw a card"; + } + + private HydaelynTheMothercrystalEffect(final HydaelynTheMothercrystalEffect effect) { + super(effect); + } + + @Override + public HydaelynTheMothercrystalEffect copy() { + return new HydaelynTheMothercrystalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return Optional.ofNullable(getTargetPointer().getFirst(game, source)) + .map(game::getPermanent) + .filter(permanent -> permanent.isLegendary(game)) + .isPresent() + && Optional + .ofNullable(source) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .filter(player -> player.drawCards(1, source, game) > 0) + .isPresent(); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VengefulStrangler.java b/Mage.Sets/src/mage/cards/v/VengefulStrangler.java index 89d335b6562..5d0fd76b8f2 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulStrangler.java +++ b/Mage.Sets/src/mage/cards/v/VengefulStrangler.java @@ -1,28 +1,34 @@ package mage.cards.v; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TransformAbility; -import mage.cards.Card; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.DoubleFacedCardHalf; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.permanent.CanBeSacrificedPredicate; +import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.Optional; import java.util.UUID; /** * @author TheElk801 */ -public final class VengefulStrangler extends CardImpl { +public final class VengefulStrangler extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); @@ -32,22 +38,32 @@ public final class VengefulStrangler extends CardImpl { } public VengefulStrangler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{B}", + "Strangling Grasp", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA}, "B" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.ROGUE); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.s.StranglingGrasp.class; + // Vengeful Strangler + this.getLeftHalfCard().setPT(2, 1); // Vengeful Strangler can't block. - this.addAbility(new CantBlockAbility()); + this.getLeftHalfCard().addAbility(new CantBlockAbility()); // When Vengeful Strangler dies, return it to the battlefield transformed under your control attached to target creature or planeswalker an opponent controls. - this.addAbility(new TransformAbility()); Ability ability = new DiesSourceTriggeredAbility(new VengefulStranglerEffect()); ability.addTarget(new TargetPermanent(filter)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Strangling Grasp + // Enchant creature or planeswalker an opponent controls + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getRightHalfCard().getSpellAbility().addTarget(auraTarget); + this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget)); + + // At the beginning of your upkeep, enchanted permanent's controller sacrifices a nonland permanent and loses 1 life. + this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new StranglingGraspEffect())); } private VengefulStrangler(final VengefulStrangler card) { @@ -86,17 +102,65 @@ class VengefulStranglerEffect extends OneShotEffect { return false; } - Card card = game.getCard(source.getSourceId()); + DoubleFacedCardHalf card = (DoubleFacedCardHalf) game.getCard(source.getSourceId()); if (card == null) { return false; } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - game.getState().setValue("attachTo:" + source.getSourceId(), permanent); + game.getState().setValue("attachTo:" + card.getOtherSide().getId(), permanent); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - permanent.addAttachment(card.getId(), source, game); + permanent.addAttachment(card.getOtherSide().getId(), source, game); } return true; } } +class StranglingGraspEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent you control"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + filter.add(CanBeSacrificedPredicate.instance); + } + + StranglingGraspEffect() { + super(Outcome.Benefit); + staticText = "enchanted permanent's controller sacrifices a nonland permanent of their choice, then that player loses 1 life"; + } + + private StranglingGraspEffect(final StranglingGraspEffect effect) { + super(effect); + } + + @Override + public StranglingGraspEffect copy() { + return new StranglingGraspEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = Optional + .ofNullable(source.getSourcePermanentOrLKI(game)) + .map(Permanent::getAttachedTo) + .map(game::getPermanentOrLKIBattlefield) + .map(Controllable::getControllerId) + .map(game::getPlayer) + .orElse(null); + if (player == null) { + return false; + } + TargetPermanent target = new TargetPermanent(filter); + target.withNotTarget(true); + 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); + } + } + player.loseLife(1, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VengefulTracker.java b/Mage.Sets/src/mage/cards/v/VengefulTracker.java index 7bf08122781..2a0e65cb2dc 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulTracker.java +++ b/Mage.Sets/src/mage/cards/v/VengefulTracker.java @@ -25,7 +25,7 @@ public final class VengefulTracker extends CardImpl { // Whenever an opponent sacrifices an artifact, Vengeful Tracker deals 2 damage to them. this.addAbility(new SacrificePermanentTriggeredAbility( - Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "them"), + Zone.BATTLEFIELD, new DamageTargetEffect(2).withTargetDescription("them"), StaticFilters.FILTER_PERMANENT_ARTIFACT, TargetController.OPPONENT, SetTargetPointer.PLAYER, false )); } diff --git a/Mage.Sets/src/mage/cards/v/VengefulVillagers.java b/Mage.Sets/src/mage/cards/v/VengefulVillagers.java new file mode 100644 index 00000000000..88bd7151378 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VengefulVillagers.java @@ -0,0 +1,52 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.TapTargetEffect; +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.filter.StaticFilters; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VengefulVillagers extends CardImpl { + + public VengefulVillagers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever this creature attacks, choose target creature an opponent controls. Tap it, then you may sacrifice an artifact or creature. If you do, put a stun counter on the chosen creature. + Ability ability = new AttacksTriggeredAbility(new TapTargetEffect("choose target creature an opponent controls. Tap it")); + ability.addEffect(new DoIfCostPaid( + new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setText("put a stun counter on the chosen creature"), + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE) + ).concatBy(", then")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private VengefulVillagers(final VengefulVillagers card) { + super(card); + } + + @Override + public VengefulVillagers copy() { + return new VengefulVillagers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VertexPaladin.java b/Mage.Sets/src/mage/cards/v/VertexPaladin.java deleted file mode 100644 index 179114e6001..00000000000 --- a/Mage.Sets/src/mage/cards/v/VertexPaladin.java +++ /dev/null @@ -1,47 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -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 java.util.UUID; - -/** - * @author TheElk801 - */ -public final class VertexPaladin extends CardImpl { - - public VertexPaladin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ANGEL); - this.subtype.add(SubType.KNIGHT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setWhite(true); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Vertex Paladin's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CreaturesYouControlCount.PLURAL))); - } - - private VertexPaladin(final VertexPaladin card) { - super(card); - } - - @Override - public VertexPaladin copy() { - return new VertexPaladin(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java b/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java deleted file mode 100644 index a4ac3365a20..00000000000 --- a/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java +++ /dev/null @@ -1,121 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.MageObjectReference; -import mage.abilities.Ability; -import mage.abilities.common.DealsDamageSourceTriggeredAbility; -import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; -import mage.abilities.condition.Condition; -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.counters.CounterType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.watchers.Watcher; - -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -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 DealsDamageSourceTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); - - // 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 DealsDamageToAPlayerTriggeredAbility( - new LoseGameTargetPlayerEffect().setText("they lose the game"), false, true - ).withInterveningIf(VesselOfTheAllConsumingCondition.instance)); - } - - private VesselOfTheAllConsuming(final VesselOfTheAllConsuming card) { - super(card); - } - - @Override - public VesselOfTheAllConsuming copy() { - return new VesselOfTheAllConsuming(this); - } - - public static Watcher makeWatcher() { - return new VesselOfTheAllConsumingWatcher(); - } -} - -enum VesselOfTheAllConsumingCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return VesselOfTheAllConsumingWatcher.checkPermanent(game, source); - } - - @Override - public String toString() { - return "it has dealt 10 or more damage to that player this turn"; - } -} - -class VesselOfTheAllConsumingWatcher extends Watcher { - - private final Map, Integer> morMap = 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) { - int damage = event.getAmount(); - morMap.compute(new AbstractMap.SimpleImmutableEntry(new MageObjectReference(permanent, game), event.getTargetId()), - (u, i) -> i == null ? damage : Integer.sum(i, damage)); - } - } - - @Override - public void reset() { - super.reset(); - morMap.clear(); - } - - static boolean checkPermanent(Game game, Ability source) { - Map, Integer> morMap = game.getState() - .getWatcher(VesselOfTheAllConsumingWatcher.class) - .morMap; - Entry key = new AbstractMap.SimpleImmutableEntry( - new MageObjectReference(game.getPermanent(source.getSourceId()), game), - source.getEffects().get(0).getTargetPointer().getFirst(game, source)); - return morMap.getOrDefault(key, 0) >= 10; - } -} diff --git a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java index 9acde8cdb6b..e5e88550434 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java +++ b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java @@ -4,21 +4,20 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceTappedCondition; -import mage.abilities.decorator.ConditionalPreventionEffect; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.decorator.ConditionalReplacementEffect; +import mage.abilities.effects.RedirectionEffect; 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.permanent.UnblockedPredicate; import mage.game.Game; import mage.game.events.DamageEvent; -import mage.game.events.DamagePlayerEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -35,10 +34,8 @@ public final class VeteranBodyguard extends CardImpl { this.toughness = new MageInt(5); // As long as Veteran Bodyguard is untapped, all damage that would be dealt to you by unblocked creatures is dealt to Veteran Bodyguard instead. - this.addAbility(new SimpleStaticAbility(new ConditionalPreventionEffect( - new VeteranBodyguardEffect(), - SourceTappedCondition.UNTAPPED, - "As long as {this} is untapped, all damage that would be dealt to you by unblocked creatures is dealt to {this} instead." + this.addAbility(new SimpleStaticAbility(new ConditionalReplacementEffect(new VeteranBodyguardEffect(), SourceTappedCondition.UNTAPPED) + .setText("As long as {this} is untapped, all damage that would be dealt to you by unblocked creatures is dealt to {this} instead." ))); } @@ -52,7 +49,7 @@ public final class VeteranBodyguard extends CardImpl { } } -class VeteranBodyguardEffect extends PreventionEffectImpl { +class VeteranBodyguardEffect extends RedirectionEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creatures"); @@ -69,22 +66,6 @@ class VeteranBodyguardEffect extends PreventionEffectImpl { super(effect); } - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamagePlayerEvent damageEvent = (DamagePlayerEvent) event; - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.damage(damageEvent.getAmount(), event.getSourceId(), source, game, damageEvent.isCombatDamage(), damageEvent.isPreventable()); - return true; - } - 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) { if (event.getPlayerId().equals(source.getControllerId()) @@ -93,6 +74,9 @@ class VeteranBodyguardEffect extends PreventionEffectImpl { if (p != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (event.getSourceId().equals(permanent.getId())) { + TargetPermanent target = new TargetPermanent(); + target.add(source.getSourceId(), game); + this.redirectTarget = target; return true; } } diff --git a/Mage.Sets/src/mage/cards/v/Vigor.java b/Mage.Sets/src/mage/cards/v/Vigor.java index 8a654c5c59b..7b57cb6a3b9 100644 --- a/Mage.Sets/src/mage/cards/v/Vigor.java +++ b/Mage.Sets/src/mage/cards/v/Vigor.java @@ -4,18 +4,18 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; 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.counters.CounterType; import mage.game.Game; -import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.PreventDamageEvent; -import mage.game.events.PreventedDamageEvent; import mage.game.permanent.Permanent; import java.util.UUID; @@ -37,7 +37,7 @@ public final class Vigor extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // If damage would be dealt to a creature you control other than Vigor, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way. - this.addAbility(new SimpleStaticAbility(new VigorReplacementEffect())); + this.addAbility(new SimpleStaticAbility(new VigorEffect())); // When Vigor is put into a graveyard from anywhere, shuffle it into its owner's library. this.addAbility(new PutIntoGraveFromAnywhereSourceTriggeredAbility(new ShuffleIntoLibrarySourceEffect())); @@ -53,36 +53,34 @@ public final class Vigor extends CardImpl { } } -class VigorReplacementEffect extends ReplacementEffectImpl { +class VigorEffect extends PreventionEffectImpl { - VigorReplacementEffect() { - super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + VigorEffect() { + super(Duration.WhileOnBattlefield); 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"; + } - private VigorReplacementEffect(final VigorReplacementEffect effect) { + private VigorEffect(final VigorEffect effect) { super(effect); } @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(); - event.setAmount(0); - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance(preventedDamage), source.getControllerId(), source, game); - } - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), preventedDamage)); - return true; - } - return false; + public VigorEffect copy() { + return new VigorEffect(this); } @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGE_PERMANENT; + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionEffectData = preventDamageAction(event, source, game); + if (preventionEffectData.getPreventedDamage() > 0) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(preventionEffectData.getPreventedDamage()), source.getControllerId(), source, game); + } + return false; + } + return false; } @Override @@ -94,8 +92,4 @@ class VigorReplacementEffect extends ReplacementEffectImpl { && !event.getTargetId().equals(source.getSourceId()); } - @Override - public VigorReplacementEffect copy() { - return new VigorReplacementEffect(this); - } } diff --git a/Mage.Sets/src/mage/cards/v/VildinPackAlpha.java b/Mage.Sets/src/mage/cards/v/VildinPackAlpha.java deleted file mode 100644 index 9bfc27a5810..00000000000 --- a/Mage.Sets/src/mage/cards/v/VildinPackAlpha.java +++ /dev/null @@ -1,83 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.UUID; - -/** - * @author LevelX2 - */ -public final class VildinPackAlpha extends CardImpl { - - private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.WEREWOLF, "a Werewolf"); - - public VildinPackAlpha(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setRed(true); - - this.nightCard = true; - - // Whenever a Werewolf you control enters, you may transform it. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, new VildinPackAlphaEffect(), filter, - true, SetTargetPointer.PERMANENT - )); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Vildin-Pack Alpha. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private VildinPackAlpha(final VildinPackAlpha card) { - super(card); - } - - @Override - public VildinPackAlpha copy() { - return new VildinPackAlpha(this); - } -} - -class VildinPackAlphaEffect extends OneShotEffect { - - VildinPackAlphaEffect() { - super(Outcome.Benefit); - this.staticText = "you may transform it"; - } - - private VildinPackAlphaEffect(final VildinPackAlphaEffect effect) { - super(effect); - } - - @Override - public VildinPackAlphaEffect copy() { - return new VildinPackAlphaEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Permanent werewolf = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (werewolf != null) { - werewolf.transform(source, game); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/v/VildinPackOutcast.java b/Mage.Sets/src/mage/cards/v/VildinPackOutcast.java index f01e7c00595..3efd763a62f 100644 --- a/Mage.Sets/src/mage/cards/v/VildinPackOutcast.java +++ b/Mage.Sets/src/mage/cards/v/VildinPackOutcast.java @@ -1,45 +1,51 @@ - package mage.cards.v; -import java.util.UUID; - -import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; 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 fireshoes */ -public final class VildinPackOutcast extends CardImpl { +public final class VildinPackOutcast extends TransformingDoubleFacedCard { public VildinPackOutcast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); - this.subtype.add(SubType.WEREWOLF); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.HORROR}, "{4}{R}", + "Dronepack Kindred", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.WEREWOLF}, "" + ); - this.secondSideCardClazz = mage.cards.d.DronepackKindred.class; + // Vildin-Pack Outcast + this.getLeftHalfCard().setPT(4, 4); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // {R}: Vildin-Pack Outcast gets +1/-1 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); // {5}{R}{R}: Transform Vildin-Pack Outcast. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R}{R}"))); + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{5}{R}{R}"))); + + // Dronepack Kindred + this.getRightHalfCard().setPT(5, 7); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // {1}: Dronepack Kindred gets +1/+0 until end of turn. + this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new GenericManaCost(1))); } private VildinPackOutcast(final VildinPackOutcast card) { diff --git a/Mage.Sets/src/mage/cards/v/VillageIronsmith.java b/Mage.Sets/src/mage/cards/v/VillageIronsmith.java index 408f637c9d1..8b4b9ff390f 100644 --- a/Mage.Sets/src/mage/cards/v/VillageIronsmith.java +++ b/Mage.Sets/src/mage/cards/v/VillageIronsmith.java @@ -1,11 +1,10 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,23 +13,30 @@ import java.util.UUID; /** * @author nantuko */ -public final class VillageIronsmith extends CardImpl { +public final class VillageIronsmith extends TransformingDoubleFacedCard { public VillageIronsmith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{R}", + "Ironfang", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.i.Ironfang.class; + // Village Ironsmith + this.getLeftHalfCard().setPT(1, 1); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.addAbility(FirstStrikeAbility.getInstance()); + this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance()); // At the beginning of each upkeep, if no spells were cast last turn, transform Village Ironsmith. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Ironfang + this.getRightHalfCard().setPT(3, 1); + + this.getRightHalfCard().addAbility(FirstStrikeAbility.getInstance()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ironfang. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private VillageIronsmith(final VillageIronsmith card) { diff --git a/Mage.Sets/src/mage/cards/v/VillageMessenger.java b/Mage.Sets/src/mage/cards/v/VillageMessenger.java index c1f2f7b5aa5..f3cfbe1cceb 100644 --- a/Mage.Sets/src/mage/cards/v/VillageMessenger.java +++ b/Mage.Sets/src/mage/cards/v/VillageMessenger.java @@ -1,11 +1,11 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -14,23 +14,32 @@ import java.util.UUID; /** * @author fireshoes */ -public final class VillageMessenger extends CardImpl { +public final class VillageMessenger extends TransformingDoubleFacedCard { public VillageMessenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(1); - this.toughness = new MageInt(1); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{R}", + "Moonrise Intruder", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.secondSideCardClazz = mage.cards.m.MoonriseIntruder.class; + // Village Messenger + this.getLeftHalfCard().setPT(1, 1); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // At the beginning of each upkeep, if no spells were cast last turn, transform Village Messenger. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Moonrise Intruder + this.getRightHalfCard().setPT(2, 2); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility()); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Moonrise Intruder. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private VillageMessenger(final VillageMessenger card) { diff --git a/Mage.Sets/src/mage/cards/v/VillageReavers.java b/Mage.Sets/src/mage/cards/v/VillageReavers.java deleted file mode 100644 index 632bcfddb62..00000000000 --- a/Mage.Sets/src/mage/cards/v/VillageReavers.java +++ /dev/null @@ -1,62 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.NightboundAbility; -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.FilterControlledPermanent; -import mage.filter.predicate.Predicates; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class VillageReavers extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledPermanent("Wolves and Werewolves"); - - static { - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public VillageReavers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - - this.color.setRed(true); - - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - // Wolves and Werewolves you control have haste. - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter - ))); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private VillageReavers(final VillageReavers card) { - super(card); - } - - @Override - public VillageReavers copy() { - return new VillageReavers(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VillageWatch.java b/Mage.Sets/src/mage/cards/v/VillageWatch.java index 8efa14cdf32..bb51e927419 100644 --- a/Mage.Sets/src/mage/cards/v/VillageWatch.java +++ b/Mage.Sets/src/mage/cards/v/VillageWatch.java @@ -1,35 +1,61 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.HasteAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; import java.util.UUID; /** * @author TheElk801 */ -public final class VillageWatch extends CardImpl { +public final class VillageWatch extends TransformingDoubleFacedCard { + + private static final FilterPermanent filter = new FilterControlledPermanent("Wolves and Werewolves"); + + static { + filter.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); + } public VillageWatch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{R}", + "Village Reavers", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - - this.secondSideCardClazz = mage.cards.v.VillageReavers.class; + // Village Watch + this.getLeftHalfCard().setPT(4, 3); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Village Reavers + this.getRightHalfCard().setPT(5, 4); + + // Wolves and Werewolves you control have haste. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private VillageWatch(final VillageWatch card) { diff --git a/Mage.Sets/src/mage/cards/v/VillagersOfEstwald.java b/Mage.Sets/src/mage/cards/v/VillagersOfEstwald.java index ce821011a2f..67e9ae67a89 100644 --- a/Mage.Sets/src/mage/cards/v/VillagersOfEstwald.java +++ b/Mage.Sets/src/mage/cards/v/VillagersOfEstwald.java @@ -1,10 +1,9 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,21 +12,26 @@ import java.util.UUID; /** * @author nantuko */ -public final class VillagersOfEstwald extends CardImpl { +public final class VillagersOfEstwald extends TransformingDoubleFacedCard { public VillagersOfEstwald(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{G}", + "Howlpack of Estwald", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.secondSideCardClazz = mage.cards.h.HowlpackOfEstwald.class; - - this.power = new MageInt(2); - this.toughness = new MageInt(3); + // Villagers of Estwald + this.getLeftHalfCard().setPT(2, 3); // At the beginning of each upkeep, if no spells were cast last turn, transform Villagers of Estwald. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Howlpack of Estwald + this.getRightHalfCard().setPT(4, 6); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Howlpack of Estwald. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private VillagersOfEstwald(final VillagersOfEstwald card) { diff --git a/Mage.Sets/src/mage/cards/v/VincentValentine.java b/Mage.Sets/src/mage/cards/v/VincentValentine.java index 6cbb8596dd6..68d19cf445b 100644 --- a/Mage.Sets/src/mage/cards/v/VincentValentine.java +++ b/Mage.Sets/src/mage/cards/v/VincentValentine.java @@ -5,13 +5,16 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -26,27 +29,40 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class VincentValentine extends CardImpl { +public final class VincentValentine extends TransformingDoubleFacedCard { public VincentValentine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ASSASSIN}, "{2}{B}{B}", + "Galian Beast", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF, SubType.BEAST}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.ASSASSIN); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.secondSideCardClazz = mage.cards.g.GalianBeast.class; + // Vincent Valentine + this.getLeftHalfCard().setPT(2, 2); // Whenever a creature an opponent controls dies, put a number of +1/+1 counters on Vincent Valentine equal to that creature's power. - this.addAbility(new DiesCreatureTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(), VincentValentineValue.instance) .setText("put a number of +1/+1 counters on {this} equal to that creature's power"), false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE )); // Whenever Vincent Valentine attacks, you may transform it. - this.addAbility(new TransformAbility()); - this.addAbility(new AttacksTriggeredAbility(new TransformSourceEffect(), true)); + this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new TransformSourceEffect(), true)); + + // Galian Beast + this.getRightHalfCard().setPT(3, 2); + + // Trample + this.getRightHalfCard().addAbility(TrampleAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // When Galian Beast dies, return it to the battlefield tapped. + this.getRightHalfCard().addAbility(new DiesSourceTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true) + .setText("return it to the battlefield tapped"))); } private VincentValentine(final VincentValentine card) { diff --git a/Mage.Sets/src/mage/cards/v/VisageOfDread.java b/Mage.Sets/src/mage/cards/v/VisageOfDread.java index a37a21a94d0..af909fc98f5 100644 --- a/Mage.Sets/src/mage/cards/v/VisageOfDread.java +++ b/Mage.Sets/src/mage/cards/v/VisageOfDread.java @@ -1,12 +1,16 @@ package mage.cards.v; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.MenaceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetOpponent; @@ -15,24 +19,39 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class VisageOfDread extends CardImpl { +public final class VisageOfDread extends TransformingDoubleFacedCard { public VisageOfDread(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{B}"); - this.secondSideCardClazz = mage.cards.d.DreadOsseosaur.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{B}", + "Dread Osseosaur", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DINOSAUR, SubType.SKELETON, SubType.HORROR}, "B" + ); + // Visage of Dread // When Visage of Dread enters the battlefield, target opponent reveals their hand. You choose an artifact or creature card from it. That player discards that card. Ability ability = new EntersBattlefieldTriggeredAbility( new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_ARTIFACT_OR_CREATURE) ); ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Craft with two creatures {5}{B} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{5}{B}", "two creatures", "other creatures you control and/or " + "creature cards in your graveyard", 2, 2, CardType.CREATURE.getPredicate() )); + + // Dread Osseosaur + this.getRightHalfCard().setPT(5, 4); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Whenever Dread Osseosaur enters the battlefield or attacks, you may mill two cards. + this.getRightHalfCard().addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new MillCardsControllerEffect(2), true + )); } private VisageOfDread(final VisageOfDread card) { diff --git a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java b/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java deleted file mode 100644 index 99a77ff529a..00000000000 --- a/Mage.Sets/src/mage/cards/v/VisionOfTheUnspeakable.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.common.continuous.BoostSourceEffect; -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.SubType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class VisionOfTheUnspeakable extends CardImpl { - - public VisionOfTheUnspeakable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); - - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Vision of the Unspeakable gets +1/+1 for each card in your hand. - this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( - CardsInControllerHandCount.ANY_SINGULAR, - CardsInControllerHandCount.ANY_SINGULAR, - Duration.WhileOnBattlefield - ))); - } - - private VisionOfTheUnspeakable(final VisionOfTheUnspeakable card) { - super(card); - } - - @Override - public VisionOfTheUnspeakable copy() { - return new VisionOfTheUnspeakable(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VitoFanaticOfAclazotz.java b/Mage.Sets/src/mage/cards/v/VitoFanaticOfAclazotz.java index 602f5b141ec..7be536253ce 100644 --- a/Mage.Sets/src/mage/cards/v/VitoFanaticOfAclazotz.java +++ b/Mage.Sets/src/mage/cards/v/VitoFanaticOfAclazotz.java @@ -3,13 +3,18 @@ package mage.cards.v; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SacrificePermanentTriggeredAbility; -import mage.abilities.effects.common.*; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -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.permanent.token.VampireDemonToken; import mage.watchers.common.AbilityResolvedWatcher; @@ -20,12 +25,6 @@ import java.util.UUID; */ public final class VitoFanaticOfAclazotz extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("another permanent"); - - static { - filter.add(AnotherPredicate.instance); - } - public VitoFanaticOfAclazotz(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); @@ -43,7 +42,7 @@ public final class VitoFanaticOfAclazotz extends CardImpl { new IfAbilityHasResolvedXTimesEffect( Outcome.GainLife, 1, new GainLifeEffect(2) ).setText("you gain 2 life if this is the first time this ability has resolved this turn"), - filter + StaticFilters.FILTER_ANOTHER_PERMANENT ); ability.addEffect( new IfAbilityHasResolvedXTimesEffect( diff --git a/Mage.Sets/src/mage/cards/v/VivisPersistence.java b/Mage.Sets/src/mage/cards/v/VivisPersistence.java new file mode 100644 index 00000000000..6eb766d062c --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VivisPersistence.java @@ -0,0 +1,53 @@ +package mage.cards.v; + +import mage.abilities.common.EntersBattlefieldOrAttacksAllTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +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.predicate.mageobject.CommanderPredicate; +import mage.game.permanent.token.BlackWizardToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VivisPersistence extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("your commander"); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(CommanderPredicate.instance); + } + + public VivisPersistence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Create a 0/1 black Wizard creature token with "Whenever you cast a noncreature spell, this token deals 1 damage to each opponent." + this.getSpellAbility().addEffect(new CreateTokenEffect(new BlackWizardToken())); + + // Whenever your commander enters or attacks, you may pay {2}. If you do, return this card from your graveyard to your hand. + this.addAbility(new EntersBattlefieldOrAttacksAllTriggeredAbility( + Zone.GRAVEYARD, + new DoIfCostPaid(new ReturnSourceFromGraveyardToHandEffect(), new GenericManaCost(2)), + filter, false + )); + } + + private VivisPersistence(final VivisPersistence card) { + super(card); + } + + @Override + public VivisPersistence copy() { + return new VivisPersistence(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VolatileArsonist.java b/Mage.Sets/src/mage/cards/v/VolatileArsonist.java index 17e4322bcf9..ef71160e9ad 100644 --- a/Mage.Sets/src/mage/cards/v/VolatileArsonist.java +++ b/Mage.Sets/src/mage/cards/v/VolatileArsonist.java @@ -1,14 +1,14 @@ package mage.cards.v; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.MenaceAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.target.TargetPlayer; @@ -20,22 +20,23 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class VolatileArsonist extends CardImpl { +public final class VolatileArsonist extends TransformingDoubleFacedCard { public VolatileArsonist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}{R}", + "Dire-Strain Anarchist", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.d.DireStrainAnarchist.class; + // Volatile Arsonist + this.getLeftHalfCard().setPT(4, 4); // Menace - this.addAbility(new MenaceAbility(false)); + this.getLeftHalfCard().addAbility(new MenaceAbility(false)); // Haste - this.addAbility(HasteAbility.getInstance()); + this.getLeftHalfCard().addAbility(HasteAbility.getInstance()); // Whenever Volatile Arsonist attacks, it deals 1 damage to each of up to one target creature, up to one target player, and/or up to one target planeswalker. Ability ability = new AttacksTriggeredAbility(new DamageTargetEffect(1) @@ -43,10 +44,29 @@ public final class VolatileArsonist extends CardImpl { ability.addTarget(new TargetCreaturePermanent(0, 1)); ability.addTarget(new TargetPlayer(0, 1, false)); ability.addTarget(new TargetPlaneswalkerPermanent(0, 1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Dire-Strain Anarchist + this.getRightHalfCard().setPT(5, 5); + + // Menace + this.getRightHalfCard().addAbility(new MenaceAbility(false)); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); + + // Whenever Dire-Strain Anarchist attacks, it deals 2 damage to each of up to one target creature, up to one target player, and/or up to one target planeswalker. + Ability ability2 = new AttacksTriggeredAbility(new DamageTargetEffect(2).setText("it deals 2 damage to each of up to one target creature, up to one target player, and/or up to one target planeswalker")); + ability2.addTarget(new TargetCreaturePermanent(0, 1)); + ability2.addTarget(new TargetPlayer(0, 1, false)); + ability2.addTarget(new TargetPlaneswalkerPermanent(0, 1)); + this.getRightHalfCard().addAbility(ability2); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private VolatileArsonist(final VolatileArsonist card) { diff --git a/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java b/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java index 87a3a831d6e..8c99e827ac3 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java @@ -1,18 +1,21 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; @@ -23,41 +26,64 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.BloodToken; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; import java.util.UUID; /** * @author TheElk801 */ -public final class VoldarenBloodcaster extends CardImpl { +public final class VoldarenBloodcaster extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("nontoken creature you control"); + private static final FilterPermanent filter2 + = new FilterControlledPermanent(SubType.BLOOD, "Blood token you control"); static { filter.add(TokenPredicate.FALSE); + filter2.add(TokenPredicate.TRUE); } public VoldarenBloodcaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.WIZARD}, "{1}{B}", + "Bloodbat Summoner", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.WIZARD}, "B" + ); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(2); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.b.BloodbatSummoner.class; + // Voldaren Bloodcaster + this.getLeftHalfCard().setPT(2, 1); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Whenever Voldaren Bloodcaster or another nontoken creature you control dies, create a Blood token. - this.addAbility(new DiesThisOrAnotherTriggeredAbility( + this.getLeftHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( new CreateTokenEffect(new BloodToken()), false, filter )); // Whenever you create a Blood token, if you control five or more Blood tokens, transform Voldaren Bloodcaster. - this.addAbility(new TransformAbility()); - this.addAbility(new VoldarenBloodcasterTriggeredAbility()); + this.getLeftHalfCard().addAbility(new VoldarenBloodcasterTriggeredAbility()); + + // Bloodbat Summoner + this.getRightHalfCard().setPT(3, 3); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // At the beginning of combat on your turn, up to one target Blood token you control becomes a 2/2 black Bat creature with flying and haste in addition to its other types. + Ability ability = new BeginningOfCombatTriggeredAbility(new BecomesCreatureTargetEffect( + new CreatureToken(2, 2, "", SubType.BAT) + .withAbility(FlyingAbility.getInstance()) + .withAbility(HasteAbility.getInstance()) + .withColor("B"), + false, false, Duration.Custom + ).setText("up to one target Blood token you control becomes a " + + "2/2 black Bat creature with flying and haste in addition to its other types")); + ability.addTarget(new TargetPermanent(0, 1, filter2)); + this.getRightHalfCard().addAbility(ability); } private VoldarenBloodcaster(final VoldarenBloodcaster card) { diff --git a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java index a903a942286..0a343267da2 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java @@ -1,29 +1,29 @@ - package mage.cards.v; -import java.util.UUID; - -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.TransformIntoSourceTriggeredAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.MadnessAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; /** * @author fireshoes */ -public final class VoldarenPariah extends CardImpl { +public final class VoldarenPariah extends TransformingDoubleFacedCard { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creatures"); @@ -32,24 +32,37 @@ public final class VoldarenPariah extends CardImpl { } public VoldarenPariah(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); - this.subtype.add(SubType.VAMPIRE); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(3); - this.toughness = new MageInt(3); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE, SubType.HORROR}, "{3}{B}{B}", + "Abolisher of Bloodlines", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELDRAZI, SubType.VAMPIRE}, "" + ); - this.secondSideCardClazz = mage.cards.a.AbolisherOfBloodlines.class; + // Voldaren Pariah + this.getLeftHalfCard().setPT(3, 3); // Flying - this.addAbility(FlyingAbility.getInstance()); + this.getLeftHalfCard().addAbility(FlyingAbility.getInstance()); // Sacrifice three other creatures: Transform Voldaren Pariah. - this.addAbility(new TransformAbility()); - this.addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new SacrificeTargetCost(3, filter))); // Madness {B}{B}{B} - this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{B}{B}{B}"))); + this.getLeftHalfCard().addAbility(new MadnessAbility(new ManaCostsImpl<>("{B}{B}{B}"))); + + // Abolisher of Bloodlines + this.getRightHalfCard().setPT(6, 5); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // When this creature transforms into Abolisher of Bloodlines, target opponent sacrifices three creatures. + Ability ability = new TransformIntoSourceTriggeredAbility(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_CREATURES, 3, "target opponent" + )); + ability.addTarget(new TargetOpponent()); + this.getRightHalfCard().addAbility(ability); } private VoldarenPariah(final VoldarenPariah card) { diff --git a/Mage.Sets/src/mage/cards/v/VoltChargedBerserker.java b/Mage.Sets/src/mage/cards/v/VoltChargedBerserker.java deleted file mode 100644 index 0663ca39e0a..00000000000 --- a/Mage.Sets/src/mage/cards/v/VoltChargedBerserker.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.cards.v; - -import mage.MageInt; -import mage.abilities.common.CantBlockAbility; -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 VoltChargedBerserker extends CardImpl { - - public VoltChargedBerserker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.BERSERKER); - this.power = new MageInt(4); - this.toughness = new MageInt(3); - this.color.setRed(true); - this.nightCard = true; - - // Volt-Charged Berserker can't block. - this.addAbility(new CantBlockAbility()); - } - - private VoltChargedBerserker(final VoltChargedBerserker card) { - super(card); - } - - @Override - public VoltChargedBerserker copy() { - return new VoltChargedBerserker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/v/VoltaicVisionary.java b/Mage.Sets/src/mage/cards/v/VoltaicVisionary.java index 78ef1ce7b04..668ae5c4b87 100644 --- a/Mage.Sets/src/mage/cards/v/VoltaicVisionary.java +++ b/Mage.Sets/src/mage/cards/v/VoltaicVisionary.java @@ -1,18 +1,17 @@ package mage.cards.v; -import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.CantBlockAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect; import mage.abilities.effects.common.TransformSourceEffect; -import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; @@ -26,27 +25,33 @@ import java.util.*; /** * @author TheElk801 */ -public final class VoltaicVisionary extends CardImpl { +public final class VoltaicVisionary extends TransformingDoubleFacedCard { public VoltaicVisionary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WIZARD}, "{1}{R}", + "Volt-Charged Berserker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.BERSERKER}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(1); - this.secondSideCardClazz = mage.cards.v.VoltChargedBerserker.class; + // Voltaic Visionary + this.getLeftHalfCard().setPT(3, 1); // {T}: Voltaic Visionary deals 2 damage to you. Exile the top card of your library. You may play that card this turn. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility( new DamageControllerEffect(2), new TapSourceCost() ); ability.addEffect(new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // When you play a card exiled with Voltaic Visionary, transform Voltaic Visionary. - this.addAbility(new TransformAbility()); - this.addAbility(new VoltaicVisionaryTriggeredAbility()); + this.getLeftHalfCard().addAbility(new VoltaicVisionaryTriggeredAbility()); + + // Volt-Charged Berserker + this.getRightHalfCard().setPT(4, 3); + + // Volt-Charged Berserker can't block. + this.getRightHalfCard().addAbility(new CantBlockAbility()); } private VoltaicVisionary(final VoltaicVisionary card) { diff --git a/Mage.Sets/src/mage/cards/v/Vorinclex.java b/Mage.Sets/src/mage/cards/v/Vorinclex.java index 65313f60c00..f6164bfb5b5 100644 --- a/Mage.Sets/src/mage/cards/v/Vorinclex.java +++ b/Mage.Sets/src/mage/cards/v/Vorinclex.java @@ -1,29 +1,41 @@ package mage.cards.v; -import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect; +import mage.abilities.effects.common.ExileSourceAndReturnFaceUpEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.DistributeCountersEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanentAmount; import java.util.UUID; /** * @author TheElk801 */ -public final class Vorinclex extends CardImpl { +public final class Vorinclex extends TransformingDoubleFacedCard { private static final FilterCard filter = new FilterCard("Forest cards"); @@ -32,32 +44,62 @@ public final class Vorinclex extends CardImpl { } public Vorinclex(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.PRAETOR}, "{3}{G}{G}", + "The Grand Evolution", + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "G" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.PHYREXIAN); - this.subtype.add(SubType.PRAETOR); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.secondSideCardClazz = mage.cards.t.TheGrandEvolution.class; + // Vorinclex + this.getLeftHalfCard().setPT(6, 6); // Trample - this.addAbility(TrampleAbility.getInstance()); + this.getLeftHalfCard().addAbility(TrampleAbility.getInstance()); // Reach - this.addAbility(ReachAbility.getInstance()); + this.getLeftHalfCard().addAbility(ReachAbility.getInstance()); // When Vorinclex enters the battlefield, search your library for up to two Forest cards, reveal them, put them into your hand, then shuffle. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( new TargetCardInLibrary(0, 2, filter), true ))); // {6}{G}{G}: Exile Vorinclex, then return it to the battlefield transformed under its owner's control. Activate only as a sorcery. - this.addAbility(new TransformAbility()); - this.addAbility(new ActivateAsSorceryActivatedAbility( + this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility( new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED), new ManaCostsImpl<>("{6}{G}{G}") )); + + // The Grand Evolution + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this.getRightHalfCard()); + + // I -- Mill ten cards. Put up to two creature cards from among the milled cards onto the battlefield. + sagaAbility.addChapterEffect(this.getRightHalfCard(), SagaChapter.CHAPTER_I, new TheGrandEvolutionEffect()); + + // II -- Distribute seven +1/+1 counters among any number of target creatures you control. + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new DistributeCountersEffect(), + new TargetCreaturePermanentAmount(7, StaticFilters.FILTER_CONTROLLED_CREATURES) + ); + + // III -- Until end of turn, creatures you control gain "{1}: This creature fights target creature you don't control." Exile The Grand Evolution, then return it to the battlefield. + Ability ability = new SimpleActivatedAbility( + new FightTargetSourceEffect() + .setText("this creature fights target creature you don't control"), + new GenericManaCost(1) + ); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + sagaAbility.addChapterEffect( + this.getRightHalfCard(), SagaChapter.CHAPTER_III, + new GainAbilityControlledEffect( + ability, Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("Until end of turn, creatures you control gain " + + "\"{1}: This creature fights target creature you don't control.\""), + new ExileSourceAndReturnFaceUpEffect() + ); + this.getRightHalfCard().addAbility(sagaAbility); } private Vorinclex(final Vorinclex card) { @@ -69,3 +111,34 @@ public final class Vorinclex extends CardImpl { return new Vorinclex(this); } } + +class TheGrandEvolutionEffect extends OneShotEffect { + + TheGrandEvolutionEffect() { + super(Outcome.Benefit); + staticText = "mill ten cards. Put up to two creature cards from among the milled cards onto the battlefield"; + } + + private TheGrandEvolutionEffect(final TheGrandEvolutionEffect effect) { + super(effect); + } + + @Override + public TheGrandEvolutionEffect copy() { + return new TheGrandEvolutionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = player.millCards(10, source, game); + TargetCard target = new TargetCard(0, 2, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE); + target.withNotTarget(true); + player.choose(Outcome.PutCreatureInPlay, cards, target, source, game); + player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/Waildrifter.java b/Mage.Sets/src/mage/cards/w/Waildrifter.java deleted file mode 100644 index 321a1d31d12..00000000000 --- a/Mage.Sets/src/mage/cards/w/Waildrifter.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.keyword.DisturbAbility; -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 Waildrifter extends CardImpl { - - public Waildrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.HIPPOGRIFF); - this.subtype.add(SubType.SPIRIT); - this.power = new MageInt(2); - this.toughness = new MageInt(2); - this.color.setBlue(true); - this.nightCard = true; - - // Flying - this.addAbility(FlyingAbility.getInstance()); - - // If Waildrifter would be put into a graveyard from anywhere, exile it instead. - this.addAbility(DisturbAbility.makeBackAbility()); - } - - private Waildrifter(final Waildrifter card) { - super(card); - } - - @Override - public Waildrifter copy() { - return new Waildrifter(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java b/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java new file mode 100644 index 00000000000..4e9026e5e9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WalkInClosetForgottenCellar.java @@ -0,0 +1,47 @@ +package mage.cards.w; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnlockThisDoorTriggeredAbility; +import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; +import mage.cards.CardSetInfo; +import mage.cards.RoomCard; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class WalkInClosetForgottenCellar extends RoomCard { + + public WalkInClosetForgottenCellar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, "{2}{G}", "{3}{G}{G}"); + this.subtype.add(SubType.ROOM); + + // Walk-In Closet: You may play lands from your graveyard. + SimpleStaticAbility left = new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands()); + this.getLeftHalfCard().addAbility(left); + + // Forgotten Cellar: When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead. + UnlockThisDoorTriggeredAbility right = new UnlockThisDoorTriggeredAbility( + new PlayFromGraveyardControllerEffect(StaticFilters.FILTER_CARD_NON_LAND, Duration.EndOfTurn) + .setText("you may cast spells from your graveyard this turn"), false, false + ); + right.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy(", and") + .setText("if a card would be put into your graveyard from anywhere this turn, exile it instead") + ); + this.getRightHalfCard().addAbility(right); + } + + private WalkInClosetForgottenCellar(final WalkInClosetForgottenCellar card) { + super(card); + } + + @Override + public WalkInClosetForgottenCellar copy() { + return new WalkInClosetForgottenCellar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WalltopSentries.java b/Mage.Sets/src/mage/cards/w/WalltopSentries.java new file mode 100644 index 00000000000..27a43ef954c --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WalltopSentries.java @@ -0,0 +1,50 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.condition.common.LessonsInGraveCondition; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.ReachAbility; +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 WalltopSentries extends CardImpl { + + public WalltopSentries(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When this creature dies, if there's a Lesson card in your graveyard, you gain 2 life. + this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(2)) + .withInterveningIf(LessonsInGraveCondition.ONE) + .addHint(LessonsInGraveCondition.getHint())); + } + + private WalltopSentries(final WalltopSentries card) { + super(card); + } + + @Override + public WalltopSentries copy() { + return new WalltopSentries(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java b/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java new file mode 100644 index 00000000000..b815237b611 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanShiTongAllKnowing.java @@ -0,0 +1,54 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.PutIntoLibraryOneOrMoreTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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.SpiritWorldToken; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WanShiTongAllKnowing extends CardImpl { + + public WanShiTongAllKnowing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Wan Shi Tong enters, target nonland permanent's owner puts it into their library second from the top or on the bottom. + Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect(2, false)); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + + // Whenever one or more cards are put into a library from anywhere, create two 1/1 colorless Spirit creature tokens with "This token can't block or be blocked by non-Spirit creatures." + this.addAbility(new PutIntoLibraryOneOrMoreTriggeredAbility(new CreateTokenEffect(new SpiritWorldToken(), 2))); + } + + private WanShiTongAllKnowing(final WanShiTongAllKnowing card) { + super(card); + } + + @Override + public WanShiTongAllKnowing copy() { + return new WanShiTongAllKnowing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java b/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java new file mode 100644 index 00000000000..00eee523b53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanShiTongLibrarian.java @@ -0,0 +1,100 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlashAbility; +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.SubType; +import mage.constants.SuperType; +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 WanShiTongLibrarian extends CardImpl { + + private static final DynamicValue xValue = new HalfValue(GetXValue.instance, false); + + public WanShiTongLibrarian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{U}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Wan Shi Tong enters, put X +1/+1 counters on him. Then draw half X cards, rounded down. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(), GetXValue.instance) + .setText("put X +1/+1 counters on him") + ); + ability.addEffect(new DrawCardSourceControllerEffect(xValue).setText("Then draw half X cards, rounded down")); + this.addAbility(ability); + + // Whenever an opponent searches their library, put a +1/+1 counter on Wan Shi Tong and draw a card. + this.addAbility(new WanShiTongLibrarianTriggeredAbility()); + } + + private WanShiTongLibrarian(final WanShiTongLibrarian card) { + super(card); + } + + @Override + public WanShiTongLibrarian copy() { + return new WanShiTongLibrarian(this); + } +} + +class WanShiTongLibrarianTriggeredAbility extends TriggeredAbilityImpl { + + WanShiTongLibrarianTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + this.setTriggerPhrase("Whenever an opponent searches their library, "); + this.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + } + + private WanShiTongLibrarianTriggeredAbility(final WanShiTongLibrarianTriggeredAbility ability) { + super(ability); + } + + @Override + public WanShiTongLibrarianTriggeredAbility copy() { + return new WanShiTongLibrarianTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LIBRARY_SEARCHED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getOpponents(getControllerId()).contains(event.getPlayerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanderingMusicians.java b/Mage.Sets/src/mage/cards/w/WanderingMusicians.java new file mode 100644 index 00000000000..2402e267f45 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanderingMusicians.java @@ -0,0 +1,40 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WanderingMusicians extends CardImpl { + + public WanderingMusicians(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R/W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Whenever this creature attacks, creatures you control get +1/+0 until end of turn. + this.addAbility(new AttacksTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn))); + } + + private WanderingMusicians(final WanderingMusicians card) { + super(card); + } + + @Override + public WanderingMusicians copy() { + return new WanderingMusicians(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarBalloon.java b/Mage.Sets/src/mage/cards/w/WarBalloon.java new file mode 100644 index 00000000000..c1374c9a8a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarBalloon.java @@ -0,0 +1,63 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WarBalloon extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.FIRE, 3); + + public WarBalloon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}: Put a fire counter on this Vehicle. + this.addAbility(new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.FIRE.createInstance()), new GenericManaCost(1) + )); + + // As long as this Vehicle has three or more fire counters on it, it's an artifact creature. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new AddCardTypeSourceEffect(Duration.WhileOnBattlefield, CardType.ARTIFACT, CardType.CREATURE), + condition, "as long as {this} has three or more fire counters on it, it's an artifact creature" + ))); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + } + + private WarBalloon(final WarBalloon card) { + super(card); + } + + @Override + public WarBalloon copy() { + return new WarBalloon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarriorsResolve.java b/Mage.Sets/src/mage/cards/w/WarriorsResolve.java index 0c384a11e75..eef11172417 100644 --- a/Mage.Sets/src/mage/cards/w/WarriorsResolve.java +++ b/Mage.Sets/src/mage/cards/w/WarriorsResolve.java @@ -40,7 +40,7 @@ public final class WarriorsResolve extends CardImpl { // Creatures you control have training. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - new TrainingAbility(), Duration.WhileControlled, StaticFilters.FILTER_PERMANENT_CREATURES + new TrainingAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES ))); // At the beginning of your end step, if you control a creature with a +1/+1 counter on it that attacked this turn, draw a card. diff --git a/Mage.Sets/src/mage/cards/w/WartimeProtestors.java b/Mage.Sets/src/mage/cards/w/WartimeProtestors.java new file mode 100644 index 00000000000..4391d058b55 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WartimeProtestors.java @@ -0,0 +1,57 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +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.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WartimeProtestors extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ALLY, "another Ally you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public WartimeProtestors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.REBEL); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever another Ally you control enters, put a +1/+1 counter on that creature and it gains haste until end of turn. + Ability ability = new EntersBattlefieldAllTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), filter); + ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()).setText("and it gains haste until end of turn")); + this.addAbility(ability); + } + + private WartimeProtestors(final WartimeProtestors card) { + super(card); + } + + @Override + public WartimeProtestors copy() { + return new WartimeProtestors(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterTribeCaptain.java b/Mage.Sets/src/mage/cards/w/WaterTribeCaptain.java new file mode 100644 index 00000000000..617bd68b59e --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterTribeCaptain.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterTribeCaptain extends CardImpl { + + public WaterTribeCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {5}: Creatures you control get +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(5) + )); + } + + private WaterTribeCaptain(final WaterTribeCaptain card) { + super(card); + } + + @Override + public WaterTribeCaptain copy() { + return new WaterTribeCaptain(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterTribeRallier.java b/Mage.Sets/src/mage/cards/w/WaterTribeRallier.java new file mode 100644 index 00000000000..5c3d881a71b --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterTribeRallier.java @@ -0,0 +1,53 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.PutCards; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterTribeRallier extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card with power 3 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public WaterTribeRallier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Waterbend {5}: Look at the top four cards of your library. You may reveal a creature card with power 3 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 SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( + 4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ), new WaterbendCost(5))); + } + + private WaterTribeRallier(final WaterTribeRallier card) { + super(card); + } + + @Override + public WaterTribeRallier copy() { + return new WaterTribeRallier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterbenderAscension.java b/Mage.Sets/src/mage/cards/w/WaterbenderAscension.java new file mode 100644 index 00000000000..1530dd67eb2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterbenderAscension.java @@ -0,0 +1,58 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterbenderAscension extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4); + + public WaterbenderAscension(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + // Whenever a creature you control deals combat damage to a player, put a quest counter on this enchantment. Then if it has four or more quest counters on it, draw a card. + Ability ability = new DealsDamageToAPlayerAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.QUEST.createInstance()), + StaticFilters.FILTER_CONTROLLED_CREATURE, false, SetTargetPointer.NONE, true + ); + ability.addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), condition, + "Then if it has four or more quest counters on it, draw a card" + )); + this.addAbility(ability); + + // Waterbend {4}: Target creature can't be blocked this turn. + ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new WaterbendCost(4)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private WaterbenderAscension(final WaterbenderAscension card) { + super(card); + } + + @Override + public WaterbenderAscension copy() { + return new WaterbenderAscension(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java new file mode 100644 index 00000000000..a2f1cf39bed --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterbendersRestoration.java @@ -0,0 +1,42 @@ +package mage.cards.w; + +import mage.abilities.costs.common.WaterbendCost; +import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.XTargetsCountAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterbendersRestoration extends CardImpl { + + public WaterbendersRestoration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + this.subtype.add(SubType.LESSON); + + // As an additional cost to cast this spell, waterbend {X}. + this.getSpellAbility().addCost(new WaterbendCost("{X}")); + + // Exile X target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step. + this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect() + .withTargetDescription("X target creatures you control")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(new XTargetsCountAdjuster()); + } + + private WaterbendersRestoration(final WaterbendersRestoration card) { + super(card); + } + + @Override + public WaterbendersRestoration copy() { + return new WaterbendersRestoration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterbendingScroll.java b/Mage.Sets/src/mage/cards/w/WaterbendingScroll.java new file mode 100644 index 00000000000..38465a00dc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterbendingScroll.java @@ -0,0 +1,63 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.InfoEffect; +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.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterbendingScroll extends CardImpl { + + public WaterbendingScroll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); + + // {6}, {T}: Draw a card. This ability costs {1} less to activate for each Island you control. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(6)); + ability.addCost(new TapSourceCost()); + ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each Island you control")); + this.addAbility(ability.setCostAdjuster(WaterbendingScrollAdjuster.instance).addHint(WaterbendingScrollAdjuster.getHint())); + } + + private WaterbendingScroll(final WaterbendingScroll card) { + super(card); + } + + @Override + public WaterbendingScroll copy() { + return new WaterbendingScroll(this); + } +} + +enum WaterbendingScrollAdjuster implements CostAdjuster { + instance; + private static final DynamicValue cardsCount = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ISLAND)); + private static final Hint hint = new ValueHint("Islands you control", cardsCount); + + static Hint getHint() { + return hint; + } + + @Override + public void reduceCost(Ability ability, Game game) { + int count = cardsCount.calculate(game, ability, null); + CardUtil.reduceCost(ability, count); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterloggedHulk.java b/Mage.Sets/src/mage/cards/w/WaterloggedHulk.java index b90cf8e7fa8..17739f43c89 100644 --- a/Mage.Sets/src/mage/cards/w/WaterloggedHulk.java +++ b/Mage.Sets/src/mage/cards/w/WaterloggedHulk.java @@ -1,11 +1,19 @@ package mage.cards.w; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DescendCondition; import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.keyword.CraftAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; @@ -14,24 +22,44 @@ import java.util.UUID; /** * @author Susucr */ -public final class WaterloggedHulk extends CardImpl { +public final class WaterloggedHulk extends TransformingDoubleFacedCard { public WaterloggedHulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}"); - this.secondSideCardClazz = mage.cards.w.WatertightGondola.class; + super(ownerId, setInfo, + new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{U}", + "Watertight Gondola", + new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "U" + ); + // Waterlogged Hulk // {T}: Mill a card. - this.addAbility(new SimpleActivatedAbility( + this.getLeftHalfCard().addAbility(new SimpleActivatedAbility( new MillCardsControllerEffect(1), new TapSourceCost() )); // Craft with Island {3}{U} - this.addAbility(new CraftAbility( + this.getLeftHalfCard().addAbility(new CraftAbility( "{3}{U}", "Island", "another Island you control or an Island card from your graveyard", SubType.ISLAND.getPredicate() )); + + // Watertight Gondola + this.getRightHalfCard().setPT(4, 4); + + // Vigilance + this.getRightHalfCard().addAbility(VigilanceAbility.getInstance()); + + // Descend 8 -- Watertight Gondola can't be blocked as long as there are eight or more permanent cards in your graveyard. + Ability ability = new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedSourceEffect(), + DescendCondition.EIGHT + ).setText("{this} can't be blocked as long as there are eight or more permanent cards in your graveyard")); + this.getRightHalfCard().addAbility(ability.addHint(DescendCondition.getHint()).setAbilityWord(AbilityWord.DESCEND_8)); + + // Crew 1 + this.getRightHalfCard().addAbility(new CrewAbility(1)); } private WaterloggedHulk(final WaterloggedHulk card) { diff --git a/Mage.Sets/src/mage/cards/w/WatertightGondola.java b/Mage.Sets/src/mage/cards/w/WatertightGondola.java deleted file mode 100644 index f7e46376672..00000000000 --- a/Mage.Sets/src/mage/cards/w/WatertightGondola.java +++ /dev/null @@ -1,56 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.DescendCondition; -import mage.abilities.decorator.ConditionalRestrictionEffect; -import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; -import mage.abilities.keyword.CrewAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.SubType; - -import java.util.UUID; - -/** - * @author Susucr - */ -public final class WatertightGondola extends CardImpl { - - public WatertightGondola(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - this.nightCard = true; - this.color.setBlue(true); - - this.subtype.add(SubType.VEHICLE); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Descend 8 -- Watertight Gondola can't be blocked as long as there are eight or more permanent cards in your graveyard. - Ability ability = new SimpleStaticAbility(new ConditionalRestrictionEffect( - new CantBeBlockedSourceEffect(), - DescendCondition.EIGHT - ).setText("{this} can't be blocked as long as there are eight or more permanent cards in your graveyard")); - this.addAbility(ability.addHint(DescendCondition.getHint()).setAbilityWord(AbilityWord.DESCEND_8)); - - // Crew 1 - this.addAbility(new CrewAbility(1)); - - } - - private WatertightGondola(final WatertightGondola card) { - super(card); - } - - @Override - public WatertightGondola copy() { - return new WatertightGondola(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WaywardDisciple.java b/Mage.Sets/src/mage/cards/w/WaywardDisciple.java deleted file mode 100644 index fc43c45ec88..00000000000 --- a/Mage.Sets/src/mage/cards/w/WaywardDisciple.java +++ /dev/null @@ -1,55 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; -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.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.common.TargetOpponent; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class WaywardDisciple extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - - public WaywardDisciple(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(2); - this.toughness = new MageInt(4); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Whenever Wayward Disciple or another creature you control dies, target opponent loses 1 life and you gain 1 life. - Ability ability = new DiesThisOrAnotherTriggeredAbility(new LoseLifeTargetEffect(1), false, filter); - ability.addEffect(new GainLifeEffect(1).concatBy("and")); - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); - } - - private WaywardDisciple(final WaywardDisciple card) { - super(card); - } - - @Override - public WaywardDisciple copy() { - return new WaywardDisciple(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WearyPrisoner.java b/Mage.Sets/src/mage/cards/w/WearyPrisoner.java index 83b8d2469ac..6b6086b9a99 100644 --- a/Mage.Sets/src/mage/cards/w/WearyPrisoner.java +++ b/Mage.Sets/src/mage/cards/w/WearyPrisoner.java @@ -1,10 +1,11 @@ package mage.cards.w; -import mage.MageInt; +import mage.abilities.common.AttacksEachCombatStaticAbility; import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.DefenderAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; @@ -13,23 +14,32 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class WearyPrisoner extends CardImpl { +public final class WearyPrisoner extends TransformingDoubleFacedCard { public WearyPrisoner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}", + "Wrathful Jailbreaker", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(6); - - this.secondSideCardClazz = mage.cards.w.WrathfulJailbreaker.class; + // Weary Prisoner + this.getLeftHalfCard().setPT(2, 6); // Defender - this.addAbility(DefenderAbility.getInstance()); + this.getLeftHalfCard().addAbility(DefenderAbility.getInstance()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Wrathful Jailbreaker + this.getRightHalfCard().setPT(6, 6); + + // Wrathful Jailbreaker attacks each combat if able. + this.getRightHalfCard().addAbility(new AttacksEachCombatStaticAbility()); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private WearyPrisoner(final WearyPrisoner card) { diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfBlossoms.java b/Mage.Sets/src/mage/cards/w/WeaverOfBlossoms.java index 3f00c090a34..3da13b5b4b0 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfBlossoms.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfBlossoms.java @@ -1,34 +1,50 @@ package mage.cards.w; -import mage.MageInt; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.keyword.DayboundAbility; +import mage.abilities.keyword.NightboundAbility; import mage.abilities.mana.AnyColorManaAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import java.util.UUID; /** * @author TheElk801 */ -public final class WeaverOfBlossoms extends CardImpl { +public final class WeaverOfBlossoms extends TransformingDoubleFacedCard { public WeaverOfBlossoms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{G}", + "Blossom-Clad Werewolf", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(2); - this.toughness = new MageInt(3); - this.secondSideCardClazz = mage.cards.b.BlossomCladWerewolf.class; + // Weaver of Blossoms + this.getLeftHalfCard().setPT(2, 3); // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); + this.getLeftHalfCard().addAbility(new AnyColorManaAbility()); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Blossom-Clad Werewolf + this.getRightHalfCard().setPT(3, 4); + + // {T}: Add two mana of any one color. + this.getRightHalfCard().addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost() + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private WeaverOfBlossoms(final WeaverOfBlossoms card) { diff --git a/Mage.Sets/src/mage/cards/w/WeddingAnnouncement.java b/Mage.Sets/src/mage/cards/w/WeddingAnnouncement.java index 3aeec3b1c6a..5adb45a4eef 100644 --- a/Mage.Sets/src/mage/cards/w/WeddingAnnouncement.java +++ b/Mage.Sets/src/mage/cards/w/WeddingAnnouncement.java @@ -1,41 +1,46 @@ package mage.cards.w; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.token.HumanToken; import mage.watchers.common.AttackedThisTurnWatcher; +import java.util.UUID; + /** * * @author weirddan455 */ -public final class WeddingAnnouncement extends CardImpl { +public final class WeddingAnnouncement extends TransformingDoubleFacedCard { public WeddingAnnouncement(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); - - this.secondSideCardClazz = mage.cards.w.WeddingFestivity.class; + super(ownerId, setInfo, + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{W}", + "Wedding Festivity", + new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "W" + ); + // Wedding Announcement // At the beginning of your end step, put an invitation counter on Wedding Announcement. // If you attacked with two or more creatures this turn, draw card. // Otherwise, create a 1/1 white Human creature token. // Then if Wedding Announcement has three or more invitation counters on it, transform it. - this.addAbility(new TransformAbility()); Ability ability = new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.INVITATION.createInstance())); ability.addEffect(new ConditionalOneShotEffect( new DrawCardSourceControllerEffect(1), @@ -48,7 +53,11 @@ public final class WeddingAnnouncement extends CardImpl { new SourceHasCounterCondition(CounterType.INVITATION, 3), "Then if {this} has three or more invitation counters on it, transform it" )); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Wedding Festivity + // Creatures you control get +1/+1 + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); } private WeddingAnnouncement(final WeddingAnnouncement card) { diff --git a/Mage.Sets/src/mage/cards/w/WeddingCrasher.java b/Mage.Sets/src/mage/cards/w/WeddingCrasher.java deleted file mode 100644 index 662b9eea17b..00000000000 --- a/Mage.Sets/src/mage/cards/w/WeddingCrasher.java +++ /dev/null @@ -1,57 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.keyword.NightboundAbility; -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.Predicates; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class WeddingCrasher extends CardImpl { - - private static final FilterPermanent filter = new FilterControlledPermanent("Wolf or Werewolf you control"); - - static { - filter.add(Predicates.or( - SubType.WOLF.getPredicate(), - SubType.WEREWOLF.getPredicate() - )); - } - - public WeddingCrasher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(5); - this.color.setGreen(true); - this.nightCard = true; - - // Whenever Wedding Crasher or another Wolf or Werewolf you control dies, draw a card. - this.addAbility(new DiesThisOrAnotherTriggeredAbility( - new DrawCardSourceControllerEffect(1), false, filter - )); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private WeddingCrasher(final WeddingCrasher card) { - super(card); - } - - @Override - public WeddingCrasher copy() { - return new WeddingCrasher(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WeddingFestivity.java b/Mage.Sets/src/mage/cards/w/WeddingFestivity.java deleted file mode 100644 index e456652aa21..00000000000 --- a/Mage.Sets/src/mage/cards/w/WeddingFestivity.java +++ /dev/null @@ -1,36 +0,0 @@ -package mage.cards.w; - -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.Duration; - -import java.util.UUID; - -/** - * - * @author weirddan455 - */ -public class WeddingFestivity extends CardImpl { - - public WeddingFestivity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, ""); - - this.color.setWhite(true); - this.nightCard = true; - - // Creatures you control get +1/+1 - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield))); - } - - private WeddingFestivity(final WeddingFestivity card) { - super(card); - } - - @Override - public WeddingFestivity copy() { - return new WeddingFestivity(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WeepingAngel.java b/Mage.Sets/src/mage/cards/w/WeepingAngel.java index 45623b0f5ea..664704822c0 100644 --- a/Mage.Sets/src/mage/cards/w/WeepingAngel.java +++ b/Mage.Sets/src/mage/cards/w/WeepingAngel.java @@ -1,19 +1,18 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.PreventionEffectImpl; -import mage.cards.Card; -import mage.constants.*; -import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.VigilanceAbility; +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.DamagePermanentEvent; @@ -21,6 +20,8 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * * @author jimga150 @@ -129,7 +130,7 @@ class WeepingAngelDamageEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - game.preventDamage(event, source, game, Integer.MAX_VALUE); + preventDamageAction(event, source, game); Card card = game.getPermanent(event.getTargetId()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/w/WelcomeTo.java b/Mage.Sets/src/mage/cards/w/WelcomeTo.java index 42cde76dfbd..7889a2a05d3 100644 --- a/Mage.Sets/src/mage/cards/w/WelcomeTo.java +++ b/Mage.Sets/src/mage/cards/w/WelcomeTo.java @@ -1,59 +1,77 @@ package mage.cards.w; +import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.EscapeAbility; import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.token.DinosaurToken; import mage.game.permanent.token.custom.CreatureToken; +import mage.players.Player; import mage.target.TargetPermanent; import mage.target.targetadjustment.ForEachPlayerTargetsAdjuster; import mage.target.targetpointer.EachTargetPointer; import mage.target.targetpointer.FixedTarget; +import java.util.Objects; import java.util.UUID; /** * * @author jimga150 */ -public final class WelcomeTo extends CardImpl { +public final class WelcomeTo extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterPermanent("Walls"); private static final FilterPermanent filterNoncreatureArtifact = new FilterPermanent("noncreature artifact"); + private static final FilterPermanent filterDinosaur = new FilterControlledPermanent("Dinosaur you control"); static { filter.add(SubType.WALL.getPredicate()); filterNoncreatureArtifact.add(Predicates.not(CardType.CREATURE.getPredicate())); filterNoncreatureArtifact.add(CardType.ARTIFACT.getPredicate()); + filterDinosaur.add(SubType.DINOSAUR.getPredicate()); } + private static final Hint hint = new ValueHint( + "Number of Dinosaurs you control", new PermanentsOnBattlefieldCount(filterDinosaur) + ); + // Based on Azusa's Many Journeys // Likeness of the Seeker, Vronos Masked Inquisitor, In the Darkness Bind Then, public WelcomeTo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{G}"); - - this.subtype.add(SubType.SAGA); - this.secondSideCardClazz = mage.cards.j.JurassicPark.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{G}{G}", + "Jurassic Park", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + // Welcome to . . . // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this); + SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard()); // I -- For each opponent, up to one target noncreature artifact they control becomes a 0/4 Wall artifact creature with defender for as long as you control this Saga. - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, ability -> { + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, ability -> { ability.addEffect( new BecomesCreatureTargetEffect( new CreatureToken(0, 4) @@ -69,16 +87,28 @@ public final class WelcomeTo extends CardImpl { // II -- Create a 3/3 green Dinosaur creature token with trample. It gains haste until end of turn. // Based on Mordor on the March - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new WelcomeToEffect()); + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new WelcomeToEffect()); // III -- Destroy all Walls. Exile this Saga, then return it to the battlefield transformed under your control. - this.addAbility(new TransformAbility()); - sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, ability -> { + sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, ability -> { ability.addEffect(new DestroyAllEffect(filter)); ability.addEffect(new ExileSagaAndReturnTransformedEffect()); }); - this.addAbility(sagaAbility); + this.getLeftHalfCard().addAbility(sagaAbility); + + // Jurassic Park + // Each Dinosaur card in your graveyard has escape. The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard. + // Based on Underworld Breach + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new JurassicParkEffect())); + + // {T}: Add {G} for each Dinosaur you control. + // Based on Gaea's Cradle + DynamicManaAbility ability = new DynamicManaAbility( + Mana.GreenMana(1), + new PermanentsOnBattlefieldCount(filterDinosaur) + ); + this.getRightHalfCard().addAbility(ability.addHint(hint)); } private WelcomeTo(final WelcomeTo card) { @@ -121,5 +151,44 @@ class WelcomeToEffect extends OneShotEffect { }); return true; } - +} + +class JurassicParkEffect extends ContinuousEffectImpl { + + JurassicParkEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "Each Dinosaur card in your graveyard has escape. " + + "The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard."; + } + + private JurassicParkEffect(final JurassicParkEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + controller + .getGraveyard() + .getCards(game) + .stream() + .filter(Objects::nonNull) + .filter(card -> !card.getManaCost().getText().isEmpty()) // card must have a mana cost + .filter(card -> card.hasSubtype(SubType.DINOSAUR, game)) + .forEach(card -> { + Ability ability = new EscapeAbility(card, card.getManaCost().getText(), 3); + ability.setSourceId(card.getId()); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + }); + return true; + } + + @Override + public JurassicParkEffect copy() { + return new JurassicParkEffect(this); + } } diff --git a/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java b/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java deleted file mode 100644 index 461ec0d4dc7..00000000000 --- a/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java +++ /dev/null @@ -1,61 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.condition.common.NotTransformedCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.CardsInAllHandsCount; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Zone; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class WerewolfOfAncientHunger extends CardImpl { - - public WerewolfOfAncientHunger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setGreen(true); - - this.nightCard = true; - - // Vigilance - this.addAbility(VigilanceAbility.getInstance()); - - // Trample - this.addAbility(TrampleAbility.getInstance()); - - // Werewolf of Ancient Hunger's power and toughness are each equal to the total number of cards in all players' hands. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, - new ConditionalContinuousEffect( - new SetBasePowerToughnessSourceEffect(CardsInAllHandsCount.instance), NotTransformedCondition.instance, - "{this}'s power and toughness are each equal to the total number of cards in all players' hands" - ) - )); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf of Ancient Hunger. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private WerewolfOfAncientHunger(final WerewolfOfAncientHunger card) { - super(card); - } - - @Override - public WerewolfOfAncientHunger copy() { - return new WerewolfOfAncientHunger(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java b/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java deleted file mode 100644 index 4b63d6ea51f..00000000000 --- a/Mage.Sets/src/mage/cards/w/WerewolfRansacker.java +++ /dev/null @@ -1,90 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.TransformIntoSourceTriggeredAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -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.constants.Zone; -import mage.game.Controllable; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetArtifactPermanent; - -import java.util.Optional; -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class WerewolfRansacker extends CardImpl { - - public WerewolfRansacker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(4); - - // Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller. - Ability ability = new TransformIntoSourceTriggeredAbility(new WerewolfRansackerEffect(), true, true); - ability.addTarget(new TargetArtifactPermanent()); - this.addAbility(ability); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker. - this.addAbility(new WerewolfBackTriggeredAbility()); - } - - private WerewolfRansacker(final WerewolfRansacker card) { - super(card); - } - - @Override - public WerewolfRansacker copy() { - return new WerewolfRansacker(this); - } -} - -class WerewolfRansackerEffect extends OneShotEffect { - - WerewolfRansackerEffect() { - super(Outcome.DestroyPermanent); - staticText = "destroy target artifact. If that artifact is put into a graveyard this way, " + - "{this} deals 3 damage to that artifact's controller"; - } - - private WerewolfRansackerEffect(final WerewolfRansackerEffect effect) { - super(effect); - } - - @Override - public WerewolfRansackerEffect copy() { - return new WerewolfRansackerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent == null) { - return false; - } - permanent.destroy(source, game); - if (game.getState().getZone(permanent.getId()) != Zone.GRAVEYARD) { - return true; - } - Optional.ofNullable(permanent) - .map(Controllable::getControllerId) - .map(game::getPlayer) - .ifPresent(player -> player.damage(3, source, game)); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WestvaleAbbey.java b/Mage.Sets/src/mage/cards/w/WestvaleAbbey.java index f618bb62b61..10b8acdbee9 100644 --- a/Mage.Sets/src/mage/cards/w/WestvaleAbbey.java +++ b/Mage.Sets/src/mage/cards/w/WestvaleAbbey.java @@ -1,8 +1,5 @@ - package mage.cards.w; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.PayLifeCost; @@ -12,43 +9,64 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.UntapSourceEffect; -import mage.abilities.keyword.TransformAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.HumanClericToken; -import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** * @author fireshoes */ -public final class WestvaleAbbey extends CardImpl { +public final class WestvaleAbbey extends TransformingDoubleFacedCard { public WestvaleAbbey(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.secondSideCardClazz = mage.cards.o.OrmendahlProfanePrince.class; + super(ownerId, setInfo, + new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, "", + "Ormendahl, Profane Prince", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DEMON}, "B" + ); + // Westvale Abbey // {T}: Add {C}. - this.addAbility(new ColorlessManaAbility()); + this.getLeftHalfCard().addAbility(new ColorlessManaAbility()); // {5}, {T}, Pay 1 life: Create a 1/1 white and black Human Cleric creature token. Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new HumanClericToken()), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); ability.addCost(new PayLifeCost(1)); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); // {5}, {T}, Sacrifice five creatures: Transform Westvale Abbey and untap it. - this.addAbility(new TransformAbility()); ability = new SimpleActivatedAbility(new TransformSourceEffect(), new GenericManaCost(5)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(5, StaticFilters.FILTER_PERMANENT_CREATURES)); ability.addEffect(new UntapSourceEffect().setText("untap it").concatBy(", then")); - this.addAbility(ability); + this.getLeftHalfCard().addAbility(ability); + + // Ormendahl, Profane Prince + this.getRightHalfCard().setPT(9, 7); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.getRightHalfCard().addAbility(LifelinkAbility.getInstance()); + + // Indestructible + this.getRightHalfCard().addAbility(IndestructibleAbility.getInstance()); + + // Haste + this.getRightHalfCard().addAbility(HasteAbility.getInstance()); } private WestvaleAbbey(final WestvaleAbbey card) { diff --git a/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java b/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java deleted file mode 100644 index 2cdb7950a39..00000000000 --- a/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.hint.common.CreaturesYouControlHint; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.permanent.token.HumanClericToken; - -import java.util.UUID; - -/** - * @author fireshoes - */ -public final class WestvaleCultLeader extends CardImpl { - - public WestvaleCultLeader(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.CLERIC); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setWhite(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - // Westvale Cult Leader's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(CreaturesYouControlCount.PLURAL)) - .addHint(CreaturesYouControlHint.instance)); - - // At the beginning of your end step, create a 1/1 white and black Human Cleric creature token. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new HumanClericToken()))); - } - - private WestvaleCultLeader(final WestvaleCultLeader card) { - super(card); - } - - @Override - public WestvaleCultLeader copy() { - return new WestvaleCultLeader(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WhirlwindTechnique.java b/Mage.Sets/src/mage/cards/w/WhirlwindTechnique.java new file mode 100644 index 00000000000..de87e822f74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhirlwindTechnique.java @@ -0,0 +1,44 @@ +package mage.cards.w; + +import mage.abilities.effects.common.DrawDiscardTargetEffect; +import mage.abilities.effects.keyword.AirbendTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WhirlwindTechnique extends CardImpl { + + public WhirlwindTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); + + this.subtype.add(SubType.LESSON); + + // Target player draws two cards, then discards a card. + this.getSpellAbility().addEffect(new DrawDiscardTargetEffect(2, 1)); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // Airbend up to two target creatures. + this.getSpellAbility().addEffect(new AirbendTargetEffect() + .setText("
Airbend up to two target creatures") + .setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + private WhirlwindTechnique(final WhirlwindTechnique card) { + super(card); + } + + @Override + public WhirlwindTechnique copy() { + return new WhirlwindTechnique(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java b/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java new file mode 100644 index 00000000000..abf10305edf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhiteLotusHideout.java @@ -0,0 +1,56 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WhiteLotusHideout extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a Lesson or Shrine spell"); + + static { + filter.add(Predicates.or( + SubType.LESSON.getPredicate(), + SubType.SHRINE.getPredicate() + )); + } + + public WhiteLotusHideout(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any color. Spend this mana only to cast a Lesson or Shrine spell. + this.addAbility(new ConditionalAnyColorManaAbility(1, new ConditionalSpellManaBuilder(filter))); + + // {1}, {T}: Add one mana of any color. + Ability ability = new AnyColorManaAbility(new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private WhiteLotusHideout(final WhiteLotusHideout card) { + super(card); + } + + @Override + public WhiteLotusHideout copy() { + return new WhiteLotusHideout(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WhiteLotusReinforcements.java b/Mage.Sets/src/mage/cards/w/WhiteLotusReinforcements.java new file mode 100644 index 00000000000..324a5174c45 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhiteLotusReinforcements.java @@ -0,0 +1,49 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +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.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WhiteLotusReinforcements extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Allies"); + + public WhiteLotusReinforcements(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Other Allies you control get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + ))); + } + + private WhiteLotusReinforcements(final WhiteLotusReinforcements card) { + super(card); + } + + @Override + public WhiteLotusReinforcements copy() { + return new WhiteLotusReinforcements(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java b/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java new file mode 100644 index 00000000000..2ab64090343 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhiteLotusTile.java @@ -0,0 +1,41 @@ +package mage.cards.w; + +import mage.Mana; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.GreatestSharedCreatureTypeCount; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WhiteLotusTile extends CardImpl { + + public WhiteLotusTile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // This artifact enters tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add X mana of any one color, where X is the greatest number of creatures you control that have a creature type in common. + this.addAbility(new DynamicManaAbility( + Mana.AnyMana(1), GreatestSharedCreatureTypeCount.instance, new TapSourceCost(), + "Add X mana of any one color, where X is the greatest number of " + + "creatures you control that have a creature type in common.", true + ).addHint(GreatestSharedCreatureTypeCount.getHint())); + } + + private WhiteLotusTile(final WhiteLotusTile card) { + super(card); + } + + @Override + public WhiteLotusTile copy() { + return new WhiteLotusTile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildbloodPack.java b/Mage.Sets/src/mage/cards/w/WildbloodPack.java deleted file mode 100644 index 6dd0d6f908a..00000000000 --- a/Mage.Sets/src/mage/cards/w/WildbloodPack.java +++ /dev/null @@ -1,54 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.common.WerewolfBackTriggeredAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; -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.StaticFilters; - -import java.util.UUID; - -/** - * @author nantuko - */ -public final class WildbloodPack extends CardImpl { - - public WildbloodPack(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.subtype.add(SubType.WEREWOLF); - this.color.setRed(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(5); - this.toughness = new MageInt(5); - - this.addAbility(TrampleAbility.getInstance()); - - // Attacking creatures you control get +3/+0. - this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( - 3, 0, Duration.WhileOnBattlefield, - StaticFilters.FILTER_ATTACKING_CREATURES, false - ))); - - // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Wildblood Pack. - this.addAbility(new WerewolfBackTriggeredAbility()); - - } - - private WildbloodPack(final WildbloodPack card) { - super(card); - } - - @Override - public WildbloodPack copy() { - return new WildbloodPack(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WildfireHowl.java b/Mage.Sets/src/mage/cards/w/WildfireHowl.java index c61f9d097a4..e897682c8de 100644 --- a/Mage.Sets/src/mage/cards/w/WildfireHowl.java +++ b/Mage.Sets/src/mage/cards/w/WildfireHowl.java @@ -33,6 +33,8 @@ public final class WildfireHowl extends CardImpl { GiftWasPromisedCondition.TRUE, "{this} deals 2 damage to each creature. " + "If the gift was promised, instead {this} deals 1 damage to any target and 2 damage to each creature" ).addEffect(new DamageAllEffect(2, StaticFilters.FILTER_PERMANENT_CREATURE))); + // ConditionalOneShotEffect doesn't call processAction between effects, so currently works + // if that gets changed (which it perhaps should?) then need to make this a single effect this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster( GiftWasPromisedCondition.TRUE, new TargetAnyTarget() )); diff --git a/Mage.Sets/src/mage/cards/w/WildsongHowler.java b/Mage.Sets/src/mage/cards/w/WildsongHowler.java deleted file mode 100644 index dad0a4f2a96..00000000000 --- a/Mage.Sets/src/mage/cards/w/WildsongHowler.java +++ /dev/null @@ -1,49 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.TransformsOrEntersTriggeredAbility; -import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.abilities.keyword.NightboundAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.PutCards; -import mage.constants.SubType; -import mage.filter.StaticFilters; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class WildsongHowler extends CardImpl { - - public WildsongHowler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - 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(6, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), - false)); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private WildsongHowler(final WildsongHowler card) { - super(card); - } - - @Override - public WildsongHowler copy() { - return new WildsongHowler(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WingShredder.java b/Mage.Sets/src/mage/cards/w/WingShredder.java deleted file mode 100644 index daf016f1dd5..00000000000 --- a/Mage.Sets/src/mage/cards/w/WingShredder.java +++ /dev/null @@ -1,42 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.keyword.NightboundAbility; -import mage.abilities.keyword.ReachAbility; -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 WingShredder extends CardImpl { - - public WingShredder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private WingShredder(final WingShredder card) { - super(card); - } - - @Override - public WingShredder copy() { - return new WingShredder(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WingedTempleOfOrazca.java b/Mage.Sets/src/mage/cards/w/WingedTempleOfOrazca.java deleted file mode 100644 index 8b286c53754..00000000000 --- a/Mage.Sets/src/mage/cards/w/WingedTempleOfOrazca.java +++ /dev/null @@ -1,88 +0,0 @@ -package mage.cards.w; - -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.ContinuousEffect; -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.mana.AnyColorManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; - -/** - * - * @author LevelX2 - */ -public final class WingedTempleOfOrazca extends CardImpl { - - public WingedTempleOfOrazca(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - - this.supertype.add(SuperType.LEGENDARY); - - this.nightCard = true; - - // (Transforms from Hadana's Climb.) - - // {T}: Add one mana of any color. - this.addAbility(new AnyColorManaAbility()); - - // {1}{G}{U}, {T}: Target creature you control gains flying and gets +X/+X until end of turn, where X is its power. - Ability ability = new SimpleActivatedAbility(new WingedTempleOfOrazcaEffect(), new ManaCostsImpl<>("{1}{G}{U}")); - ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetControlledCreaturePermanent()); - this.addAbility(ability); - } - - private WingedTempleOfOrazca(final WingedTempleOfOrazca card) { - super(card); - } - - @Override - public WingedTempleOfOrazca copy() { - return new WingedTempleOfOrazca(this); - } -} - -class WingedTempleOfOrazcaEffect extends OneShotEffect { - - WingedTempleOfOrazcaEffect() { - super(Outcome.Benefit); - this.staticText = "target creature you control gains flying and gets +X/+X until end of turn, where X is its power"; - } - - private WingedTempleOfOrazcaEffect(final WingedTempleOfOrazcaEffect effect) { - super(effect); - } - - @Override - public WingedTempleOfOrazcaEffect copy() { - return new WingedTempleOfOrazcaEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (creature != null && creature.isCreature(game)) { - int pow = creature.getPower().getValue(); - ContinuousEffect effect = new BoostTargetEffect(pow, pow, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature, game)); - game.addEffect(effect, source); - effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature, game)); - game.addEffect(effect, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WinnowingForces.java b/Mage.Sets/src/mage/cards/w/WinnowingForces.java deleted file mode 100644 index 34ccc655ee8..00000000000 --- a/Mage.Sets/src/mage/cards/w/WinnowingForces.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.LandsYouControlCount; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -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 WinnowingForces extends CardImpl { - - public WinnowingForces(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.ELF); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - this.color.setGreen(true); - this.color.setBlack(true); - this.nightCard = true; - - // Winnowing Forces's power and toughness are each equal to the number of lands you control. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SetBasePowerToughnessSourceEffect(LandsYouControlCount.instance) - )); - } - - private WinnowingForces(final WinnowingForces card) { - super(card); - } - - @Override - public WinnowingForces copy() { - return new WinnowingForces(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/Wirecat.java b/Mage.Sets/src/mage/cards/w/Wirecat.java index 3b8e48ae566..d13b4386135 100644 --- a/Mage.Sets/src/mage/cards/w/Wirecat.java +++ b/Mage.Sets/src/mage/cards/w/Wirecat.java @@ -9,7 +9,6 @@ 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.game.permanent.Permanent; @@ -39,39 +38,39 @@ public final class Wirecat extends CardImpl { public Wirecat copy() { return new Wirecat(this); } +} - static class WirecatEffect extends RestrictionEffect { +class WirecatEffect extends RestrictionEffect { - public WirecatEffect() { - super(Duration.WhileOnBattlefield); - staticText = "{this} can't attack or block if an enchantment is on the battlefield"; - } - - private WirecatEffect(final WirecatEffect effect) { - super(effect); - } - - @Override - public WirecatEffect copy() { - return new WirecatEffect(this); - } - - @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { - return false; - } - - @Override - public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { - return false; - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return game.getBattlefield().contains(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source, game, 1); - } - return false; + WirecatEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't attack or block if an enchantment is on the battlefield"; + } + + private WirecatEffect(final WirecatEffect effect) { + super(effect); + } + + @Override + public WirecatEffect copy() { + return new WirecatEffect(this); + } + + @Override + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return game.getBattlefield().contains(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source, game, 1); } + return false; } } diff --git a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java b/Mage.Sets/src/mage/cards/w/WithengarUnbound.java deleted file mode 100644 index 4b170ef2642..00000000000 --- a/Mage.Sets/src/mage/cards/w/WithengarUnbound.java +++ /dev/null @@ -1,81 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.IntimidateAbility; -import mage.abilities.keyword.TrampleAbility; -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.GameEvent; - -import java.util.UUID; - -/** - * @author BetaSteward - */ -public final class WithengarUnbound extends CardImpl { - - public WithengarUnbound(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DEMON); - this.color.setBlack(true); - - // this card is the second face of double-faced card - this.nightCard = true; - - this.power = new MageInt(13); - this.toughness = new MageInt(13); - - this.addAbility(FlyingAbility.getInstance()); - this.addAbility(IntimidateAbility.getInstance()); - this.addAbility(TrampleAbility.getInstance()); - - // Whenever a player loses the game, put thirteen +1/+1 counters on Withengar Unbound. - this.addAbility(new WithengarUnboundTriggeredAbility()); - } - - private WithengarUnbound(final WithengarUnbound card) { - super(card); - } - - @Override - public WithengarUnbound copy() { - return new WithengarUnbound(this); - } -} - -class WithengarUnboundTriggeredAbility extends TriggeredAbilityImpl { - - WithengarUnboundTriggeredAbility() { - super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(13)), false); - setTriggerPhrase("Whenever a player loses the game, "); - } - - private WithengarUnboundTriggeredAbility(final WithengarUnboundTriggeredAbility ability) { - super(ability); - } - - @Override - public WithengarUnboundTriggeredAbility copy() { - return new WithengarUnboundTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.LOST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WojekBodyguard.java b/Mage.Sets/src/mage/cards/w/WojekBodyguard.java index 7041d3bd4d4..17a4b2189b6 100644 --- a/Mage.Sets/src/mage/cards/w/WojekBodyguard.java +++ b/Mage.Sets/src/mage/cards/w/WojekBodyguard.java @@ -1,14 +1,14 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; -import mage.constants.SubType; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.abilities.keyword.MentorAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; /** * @@ -28,8 +28,7 @@ public final class WojekBodyguard extends CardImpl { this.addAbility(new MentorAbility()); // Wojek Bodyguard can't attack or block alone. - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private WojekBodyguard(final WojekBodyguard card) { diff --git a/Mage.Sets/src/mage/cards/w/Wolfbat.java b/Mage.Sets/src/mage/cards/w/Wolfbat.java new file mode 100644 index 00000000000..3afcc12e14e --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wolfbat.java @@ -0,0 +1,54 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.DrawNthCardTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldWithCounterEffect; +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 mage.constants.Zone; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Wolfbat extends CardImpl { + + public Wolfbat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.WOLF); + this.subtype.add(SubType.BAT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you draw your second card each turn, you may pay {B}. If you do, return this card from your graveyard to the battlefield with a finality counter on it. + this.addAbility(new DrawNthCardTriggeredAbility( + Zone.GRAVEYARD, + new DoIfCostPaid( + new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect( + CounterType.FINALITY.createInstance(), false + ), new ManaCostsImpl<>("{B}") + ), false, TargetController.YOU, 2 + )); + } + + private Wolfbat(final Wolfbat card) { + super(card); + } + + @Override + public Wolfbat copy() { + return new Wolfbat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WolfbittenCaptive.java b/Mage.Sets/src/mage/cards/w/WolfbittenCaptive.java index ab976d8286d..0953e800441 100644 --- a/Mage.Sets/src/mage/cards/w/WolfbittenCaptive.java +++ b/Mage.Sets/src/mage/cards/w/WolfbittenCaptive.java @@ -1,13 +1,12 @@ package mage.cards.w; -import mage.MageInt; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; @@ -18,24 +17,32 @@ import java.util.UUID; /** * @author Loki */ -public final class WolfbittenCaptive extends CardImpl { +public final class WolfbittenCaptive extends TransformingDoubleFacedCard { public WolfbittenCaptive(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{G}", + "Krallenhorde Killer", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.power = new MageInt(1); - this.toughness = new MageInt(1); - - this.secondSideCardClazz = mage.cards.k.KrallenhordeKiller.class; + // Wolfbitten Captive + this.getLeftHalfCard().setPT(1, 1); // {1}{G}: Wolfbitten Captive gets +2/+2 until end of turn. Activate this ability only once each turn. - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{G}"))); + this.getLeftHalfCard().addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{G}"))); // At the beginning of each upkeep, if no spells were cast last turn, transform Wolfbitten Captive. - this.addAbility(new TransformAbility()); - this.addAbility(new WerewolfFrontTriggeredAbility()); + this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility()); + + // Krallenhorde Killer + this.getRightHalfCard().setPT(2, 2); + + // {3}{G}: Krallenhorde Killer gets +4/+4 until end of turn. Activate this ability only once each turn. + this.getRightHalfCard().addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(4, 4, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{G}"))); + + // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Krallenhorde Killer. + this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility()); } private WolfbittenCaptive(final WolfbittenCaptive card) { diff --git a/Mage.Sets/src/mage/cards/w/WolfkinOutcast.java b/Mage.Sets/src/mage/cards/w/WolfkinOutcast.java index 21595ce0f23..b0d3e0bfa84 100644 --- a/Mage.Sets/src/mage/cards/w/WolfkinOutcast.java +++ b/Mage.Sets/src/mage/cards/w/WolfkinOutcast.java @@ -1,15 +1,17 @@ package mage.cards.w; -import mage.MageInt; +import mage.abilities.common.DiesThisOrAnotherTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.abilities.hint.ConditionHint; import mage.abilities.hint.Hint; import mage.abilities.keyword.DayboundAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.NightboundAbility; import mage.cards.CardSetInfo; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -22,15 +24,20 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class WolfkinOutcast extends CardImpl { +public final class WolfkinOutcast extends TransformingDoubleFacedCard { private static final FilterPermanent filter = new FilterControlledPermanent("you control a Wolf or Werewolf"); + private static final FilterPermanent filter2 = new FilterControlledPermanent("Wolf or Werewolf you control"); static { filter.add(Predicates.or( SubType.WOLF.getPredicate(), SubType.WEREWOLF.getPredicate() )); + filter2.add(Predicates.or( + SubType.WOLF.getPredicate(), + SubType.WEREWOLF.getPredicate() + )); } private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); @@ -39,21 +46,35 @@ public final class WolfkinOutcast extends CardImpl { ); public WolfkinOutcast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + super(ownerId, setInfo, + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{5}{G}", + "Wedding Crasher", + new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G" + ); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(5); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.w.WeddingCrasher.class; + // Wolfkin Outcast + this.getLeftHalfCard().setPT(5, 4); // This spell costs {2} less to cast if you control a Wolf or Werewolf. - this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) - ).setRuleAtTheTop(true)); + this.getLeftHalfCard().addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true)) + .setRuleAtTheTop(true) + .addHint(hint) + ); // Daybound - this.addAbility(new DayboundAbility()); + this.getLeftHalfCard().addAbility(new DayboundAbility()); + + // Wedding Crasher + this.getRightHalfCard().setPT(6, 5); + + // Whenever Wedding Crasher or another Wolf or Werewolf you control dies, draw a card. + this.getRightHalfCard().addAbility(new DiesThisOrAnotherTriggeredAbility( + new DrawCardSourceControllerEffect(1), false, filter2 + )); + + // Nightbound + this.getRightHalfCard().addAbility(new NightboundAbility()); } private WolfkinOutcast(final WolfkinOutcast card) { diff --git a/Mage.Sets/src/mage/cards/w/WorldChampionCelestialWeapon.java b/Mage.Sets/src/mage/cards/w/WorldChampionCelestialWeapon.java deleted file mode 100644 index 5b81bc4e926..00000000000 --- a/Mage.Sets/src/mage/cards/w/WorldChampionCelestialWeapon.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.cards.w; - -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostEquippedEffect; -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.constants.SuperType; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class WorldChampionCelestialWeapon extends CardImpl { - - public WorldChampionCelestialWeapon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.EQUIPMENT); - this.nightCard = true; - this.color.setRed(true); - - // Double Overdrive -- Equipped creature gets +2/+0 and has double strike. - Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 0)); - ability.addEffect(new GainAbilityAttachedEffect( - DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT - ).setText("and has double strike")); - this.addAbility(ability.withFlavorWord("Double Overdrive")); - - // Equip {3} - this.addAbility(new EquipAbility(3)); - } - - private WorldChampionCelestialWeapon(final WorldChampionCelestialWeapon card) { - super(card); - } - - @Override - public WorldChampionCelestialWeapon copy() { - return new WorldChampionCelestialWeapon(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WrathfulJailbreaker.java b/Mage.Sets/src/mage/cards/w/WrathfulJailbreaker.java deleted file mode 100644 index 3e0bf2c9f1b..00000000000 --- a/Mage.Sets/src/mage/cards/w/WrathfulJailbreaker.java +++ /dev/null @@ -1,43 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.common.AttacksEachCombatStaticAbility; -import mage.abilities.keyword.NightboundAbility; -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 WrathfulJailbreaker extends CardImpl { - - public WrathfulJailbreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.subtype.add(SubType.WEREWOLF); - this.power = new MageInt(6); - this.toughness = new MageInt(6); - this.color.setRed(true); - - this.nightCard = true; - - // Wrathful Jailbreaker attacks each combat if able. - this.addAbility(new AttacksEachCombatStaticAbility()); - - // Nightbound - this.addAbility(new NightboundAbility()); - } - - private WrathfulJailbreaker(final WrathfulJailbreaker card) { - super(card); - } - - @Override - public WrathfulJailbreaker copy() { - return new WrathfulJailbreaker(this); - } -} diff --git a/Mage.Sets/src/mage/cards/w/WretchedBonemass.java b/Mage.Sets/src/mage/cards/w/WretchedBonemass.java deleted file mode 100644 index 7de729fd930..00000000000 --- a/Mage.Sets/src/mage/cards/w/WretchedBonemass.java +++ /dev/null @@ -1,175 +0,0 @@ -package mage.cards.w; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; -import mage.abilities.keyword.*; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.ExileZone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.util.CardUtil; - -import java.util.Set; -import java.util.UUID; - -/** - * - * @author jeffwadsworth - */ -public final class WretchedBonemass extends CardImpl { - - public WretchedBonemass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, null); - this.nightCard = true; - this.color.setBlack(true); - - this.subtype.add(SubType.SKELETON); - this.subtype.add(SubType.HORROR); - this.power = new MageInt(0); - this.toughness = new MageInt(0); - - // Wretched Bonemass’s power and toughness are each equal to the total power of the exiled cards used to craft it. - this.addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(WretchedBonemassDynamicValue.instance).setText("{this}'s power and toughness are each equal to the total power of the exiled cards used to craft it."))); - - // Wretched Bonemass has flying as long as an exiled card used to craft it 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(new WretchedBonemassGainAbilityEffect())); - - } - - private WretchedBonemass(final WretchedBonemass card) { - super(card); - } - - @Override - public WretchedBonemass copy() { - return new WretchedBonemass(this); - } -} - -enum WretchedBonemassDynamicValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - int totalPower = 0; - Permanent permanent = sourceAbility.getSourcePermanentIfItStillExists(game); - if (permanent == null) { - return 0; - } - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, permanent.getId(), permanent.getZoneChangeCounter(game) - 2 - )); - if (exileZone == null) { - return 0; - } - for (Card card : exileZone.getCards(game)) { - totalPower += card.getPower().getValue(); - } - return totalPower; - } - - @Override - public WretchedBonemassDynamicValue copy() { - return this; - } - - @Override - public String getMessage() { - return "total power of the exiled cards used to craft it"; - } - - @Override - public String toString() { - return "0"; - } -} - -class WretchedBonemassGainAbilityEffect extends ContinuousEffectImpl { - - WretchedBonemassGainAbilityEffect() { - super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "{this} has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance."; - } - - private WretchedBonemassGainAbilityEffect(final WretchedBonemassGainAbilityEffect effect) { - super(effect); - } - - @Override - public WretchedBonemassGainAbilityEffect copy() { - return new WretchedBonemassGainAbilityEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent wretchedBonemass = source.getSourcePermanentIfItStillExists(game); - if (wretchedBonemass != null) { - ExileZone exileZone = game - .getExile() - .getExileZone(CardUtil.getExileZoneId( - game, wretchedBonemass.getId(), wretchedBonemass.getZoneChangeCounter(game) - 2 - )); - if (exileZone != null - && !exileZone.isEmpty()) { - Set cardsInExile = exileZone.getCards(game); - for (Card card : cardsInExile) { - for (Ability a : card.getAbilities()) { - if (a instanceof FlyingAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof FirstStrikeAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof DoubleStrikeAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof DeathtouchAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof HasteAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof HexproofAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof IndestructibleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof LifelinkAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof MenaceAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof ProtectionAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof IndestructibleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof ReachAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof TrampleAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - if (a instanceof VigilanceAbility) { - wretchedBonemass.addAbility(a, source.getSourceId(), game); - } - } - } - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java b/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java deleted file mode 100644 index 277a6a11108..00000000000 --- a/Mage.Sets/src/mage/cards/y/YiazmatUltimateMark.java +++ /dev/null @@ -1,65 +0,0 @@ -package mage.cards.y; - -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.TapSourceEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.IndestructibleAbility; -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.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class YiazmatUltimateMark extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("another creature or artifact"); - - static { - filter.add(AnotherPredicate.instance); - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.ARTIFACT.getPredicate() - )); - } - - public YiazmatUltimateMark(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DRAGON); - this.power = new MageInt(5); - this.toughness = new MageInt(6); - this.nightCard = true; - this.color.setBlack(true); - - // {1}{B}, Sacrifice another creature or artifact: Yiazmat gains indestructible until end of turn. Tap it. - Ability ability = new SimpleActivatedAbility( - new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl<>("{1}{B}") - ); - ability.addCost(new SacrificeTargetCost(filter)); - ability.addEffect(new TapSourceEffect().setText("tap it")); - this.addAbility(ability); - } - - private YiazmatUltimateMark(final YiazmatUltimateMark card) { - super(card); - } - - @Override - public YiazmatUltimateMark copy() { - return new YiazmatUltimateMark(this); - } -} diff --git a/Mage.Sets/src/mage/cards/y/YipYip.java b/Mage.Sets/src/mage/cards/y/YipYip.java new file mode 100644 index 00000000000..1eb242e208e --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YipYip.java @@ -0,0 +1,71 @@ +package mage.cards.y; + +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.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YipYip extends CardImpl { + + public YipYip(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + this.subtype.add(SubType.LESSON); + + // Target creature you control gets +2/+2 until end of turn. If that creature is an Ally, it also gains flying until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addEffect(new YipYipEffect()); + } + + private YipYip(final YipYip card) { + super(card); + } + + @Override + public YipYip copy() { + return new YipYip(this); + } +} + +class YipYipEffect extends OneShotEffect { + + YipYipEffect() { + super(Outcome.Benefit); + staticText = "If that creature is an Ally, it also gains flying until end of turn"; + } + + private YipYipEffect(final YipYipEffect effect) { + super(effect); + } + + @Override + public YipYipEffect copy() { + return new YipYipEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Optional.ofNullable(getTargetPointer().getFirst(game, source)) + .map(game::getPermanent) + .filter(permanent -> permanent.hasSubtype(SubType.ALLY, game)) + .ifPresent(permanent -> game.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()) + .setTargetPointer(new FixedTarget(permanent, game)), source)); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/y/YixlidJailer.java b/Mage.Sets/src/mage/cards/y/YixlidJailer.java index 48cd9d5f3b1..72bae85bba9 100644 --- a/Mage.Sets/src/mage/cards/y/YixlidJailer.java +++ b/Mage.Sets/src/mage/cards/y/YixlidJailer.java @@ -72,7 +72,7 @@ class YixlidJailerEffect extends ContinuousEffectImpl { if (player != null) { for (Card card : player.getGraveyard().getCards(game)) { if (card != null) { - card.looseAllAbilities(game); + card.loseAllAbilities(game); } } } diff --git a/Mage.Sets/src/mage/cards/z/ZenosYaeGalvus.java b/Mage.Sets/src/mage/cards/z/ZenosYaeGalvus.java index d808e24232d..72f226bec8f 100644 --- a/Mage.Sets/src/mage/cards/z/ZenosYaeGalvus.java +++ b/Mage.Sets/src/mage/cards/z/ZenosYaeGalvus.java @@ -1,27 +1,31 @@ package mage.cards.z; -import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.ChooseCreatureEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.effects.common.WinGameSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.keyword.TransformAbility; -import mage.cards.CardImpl; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.cards.TransformingDoubleFacedCard; +import mage.constants.*; 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.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponent; import mage.util.CardUtil; import java.util.Optional; @@ -30,7 +34,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ZenosYaeGalvus extends CardImpl { +public final class ZenosYaeGalvus extends TransformingDoubleFacedCard { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); private static final FilterPermanent filter2 = new FilterPermanent(); @@ -41,15 +45,14 @@ public final class ZenosYaeGalvus extends CardImpl { } public ZenosYaeGalvus(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + super(ownerId, setInfo, + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.NOBLE, SubType.WARRIOR}, "{3}{B}{B}", + "Shinryu, Transcendent Rival", + new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.DRAGON}, "B" + ); - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.NOBLE); - this.subtype.add(SubType.WARRIOR); - this.power = new MageInt(4); - this.toughness = new MageInt(4); - this.secondSideCardClazz = mage.cards.s.ShinryuTranscendentRival.class; + // Zenos yae Galvus + this.getLeftHalfCard().setPT(4, 4); // My First Friend -- When Zenos yae Galvus enters, choose a creature an opponent controls. Until end of turn, creatures other than Zenos yae Galvus and the chosen creature get -2/-2. Ability ability = new EntersBattlefieldTriggeredAbility( @@ -58,13 +61,24 @@ public final class ZenosYaeGalvus extends CardImpl { ability.addEffect(new BoostAllEffect( -2, -2, Duration.EndOfTurn, filter, true ).setText("until end of turn, creatures other than {this} and the chosen creature get -2/-2")); - this.addAbility(ability.withFlavorWord("My First Friend")); + this.getLeftHalfCard().addAbility(ability.withFlavorWord("My First Friend")); // When the chosen creature leaves the battlefield, transform Zenos yae Galvus. - this.addAbility(new TransformAbility()); - this.addAbility(new LeavesBattlefieldAllTriggeredAbility( + this.getLeftHalfCard().addAbility(new LeavesBattlefieldAllTriggeredAbility( new TransformSourceEffect(), filter2 ).setTriggerPhrase("When the chosen creature leaves the battlefield, ")); + + // Shinryu, Transcendent Rival + this.getRightHalfCard().setPT(8, 8); + + // Flying + this.getRightHalfCard().addAbility(FlyingAbility.getInstance()); + + // As this creature transforms into Shinryu, choose an opponent. + this.getRightHalfCard().addAbility(new SimpleStaticAbility(new ShinryuTranscendentRivalEffect())); + + // Burning Chains -- When the chosen player loses the game, you win the game. + this.getRightHalfCard().addAbility(new ShinryuTranscendentRivalTriggeredAbility()); } private ZenosYaeGalvus(final ZenosYaeGalvus card) { @@ -101,3 +115,83 @@ enum ZenosYaeGalvusPredicate implements ObjectSourcePlayerPredicate { .orElse(false); } } + +class ShinryuTranscendentRivalEffect extends ReplacementEffectImpl { + + ShinryuTranscendentRivalEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "as this creature transforms into {this}, choose an opponent"; + } + + private ShinryuTranscendentRivalEffect(final ShinryuTranscendentRivalEffect effect) { + super(effect); + } + + @Override + public ShinryuTranscendentRivalEffect copy() { + return new ShinryuTranscendentRivalEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (controller == null || permanent == null) { + return false; + } + TargetPlayer target = new TargetOpponent(true); + controller.choose(Outcome.Benefit, target, source, game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { + return false; + } + game.informPlayers(permanent.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); + game.getState().setValue(permanent.getId() + "_" + permanent.getZoneChangeCounter(game) + "_opponent", opponent.getId()); + permanent.addInfo("chosen opponent", CardUtil.addToolTipMarkTags("Chosen Opponent " + opponent.getLogName()), game); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TRANSFORMING; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.getSourceId().equals(event.getTargetId()) + && source.getSourcePermanentIfItStillExists(game) != null; + } +} + +class ShinryuTranscendentRivalTriggeredAbility extends TriggeredAbilityImpl { + + ShinryuTranscendentRivalTriggeredAbility() { + super(Zone.BATTLEFIELD, new WinGameSourceControllerEffect()); + this.setTriggerPhrase("When the chosen player loses the game, "); + this.withFlavorWord("Burning Chains"); + } + + private ShinryuTranscendentRivalTriggeredAbility(final ShinryuTranscendentRivalTriggeredAbility ability) { + super(ability); + } + + @Override + public ShinryuTranscendentRivalTriggeredAbility copy() { + return new ShinryuTranscendentRivalTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + int zcc = game.getState().getZoneChangeCounter(this.getSourceId()); + return Optional + .of(this.getSourceId() + "_" + zcc + "_opponent") + .map(game.getState()::getValue) + .map(event.getPlayerId()::equals) + .orElse(false); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZhaoRuthlessAdmiral.java b/Mage.Sets/src/mage/cards/z/ZhaoRuthlessAdmiral.java new file mode 100644 index 00000000000..e002bedb33c --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZhaoRuthlessAdmiral.java @@ -0,0 +1,56 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.FirebendingAbility; +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.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZhaoRuthlessAdmiral extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("another permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public ZhaoRuthlessAdmiral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B/R}{B/R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Firebending 2 + this.addAbility(new FirebendingAbility(2)); + + // Whenever you sacrifice another permanent, creatures you control get +1/+0 until end of turn. + this.addAbility(new SacrificePermanentTriggeredAbility( + new BoostControlledEffect(1, 0, Duration.EndOfTurn), filter + )); + } + + private ZhaoRuthlessAdmiral(final ZhaoRuthlessAdmiral card) { + super(card); + } + + @Override + public ZhaoRuthlessAdmiral copy() { + return new ZhaoRuthlessAdmiral(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZhaoTheMoonSlayer.java b/Mage.Sets/src/mage/cards/z/ZhaoTheMoonSlayer.java new file mode 100644 index 00000000000..eea55758eee --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZhaoTheMoonSlayer.java @@ -0,0 +1,66 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.PermanentsEnterBattlefieldTappedEffect; +import mage.abilities.effects.common.continuous.NonbasicLandsAreMountainsEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZhaoTheMoonSlayer extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.CONQUEROR); + + public ZhaoTheMoonSlayer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Nonbasic lands enter tapped. + this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(StaticFilters.FILTER_LANDS_NONBASIC))); + + // {7}: Put a conqueror counter on Zhao. + this.addAbility(new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.CONQUEROR.createInstance()), new GenericManaCost(7) + )); + + // As long as Zhao has a conqueror counter on him, nonbasic lands are Mountains. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new NonbasicLandsAreMountainsEffect(), condition, + "as long as {this} has a conqueror counter on him, nonbasic lands are Mountains" + ))); + } + + private ZhaoTheMoonSlayer(final ZhaoTheMoonSlayer card) { + super(card); + } + + @Override + public ZhaoTheMoonSlayer copy() { + return new ZhaoTheMoonSlayer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZilorthaApexOfIkoria.java b/Mage.Sets/src/mage/cards/z/ZilorthaApexOfIkoria.java deleted file mode 100644 index 3509c40ef64..00000000000 --- a/Mage.Sets/src/mage/cards/z/ZilorthaApexOfIkoria.java +++ /dev/null @@ -1,82 +0,0 @@ -package mage.cards.z; - -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; -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.players.Player; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ZilorthaApexOfIkoria extends CardImpl { - - public ZilorthaApexOfIkoria(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); - - this.supertype.add(SuperType.LEGENDARY); - this.subtype.add(SubType.DINOSAUR); - this.power = new MageInt(8); - this.toughness = new MageInt(8); - this.color.setGreen(true); - this.nightCard = true; - - // Reach - this.addAbility(ReachAbility.getInstance()); - - // For each non-Human creature you control, you may have that creature assign its combat damage as though it weren't blocked. - this.addAbility(new SimpleStaticAbility(new ZilorthaApexOfIkoriaEffect())); - } - - private ZilorthaApexOfIkoria(final ZilorthaApexOfIkoria card) { - super(card); - } - - @Override - public ZilorthaApexOfIkoria copy() { - return new ZilorthaApexOfIkoria(this); - } -} - -class ZilorthaApexOfIkoriaEffect extends AsThoughEffectImpl { - - ZilorthaApexOfIkoriaEffect() { - super(AsThoughEffectType.DAMAGE_NOT_BLOCKED, Duration.WhileOnBattlefield, Outcome.Damage); - this.staticText = "for each non-Human creature you control, you may have that " + - "creature assign its combat damage as though it weren't blocked"; - } - - private ZilorthaApexOfIkoriaEffect(ZilorthaApexOfIkoriaEffect effect) { - super(effect); - } - - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(sourceId); - return controller != null - && permanent != null - && permanent.isControlledBy(controller.getId()) - && !permanent.hasSubtype(SubType.HUMAN, game) - && controller.chooseUse(Outcome.Damage, "Have " + permanent.getLogName() - + " assign damage as though it weren't blocked?", source, game); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public ZilorthaApexOfIkoriaEffect copy() { - return new ZilorthaApexOfIkoriaEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/z/ZukoConflicted.java b/Mage.Sets/src/mage/cards/z/ZukoConflicted.java new file mode 100644 index 00000000000..9d528c62fdc --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukoConflicted.java @@ -0,0 +1,104 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility; +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.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZukoConflicted extends CardImpl { + + public ZukoConflicted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // At the beginning of your first main phase, choose one that hasn't been chosen and you lose 2 life -- + // * Draw a card. + Ability ability = new BeginningOfFirstMainTriggeredAbility(new DrawCardSourceControllerEffect(1).setText("draw")); + ability.addEffect(new LoseLifeSourceControllerEffect(2).setText(" a card")); + ability.getModes().setChooseText("choose one that hasn't been chosen and you lose 2 life —"); + ability.getModes().setLimitUsageByOnce(false); + + // * Put a +1/+1 counter on Zuko. + ability.addMode(new Mode(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter")) + .addEffect(new LoseLifeSourceControllerEffect(2).setText(" on {this}"))); + + // * Add {R}. + ability.addMode(new Mode(new BasicManaEffect(Mana.RedMana(1)).setText("add")) + .addEffect(new LoseLifeSourceControllerEffect(2).setText("{R}"))); + + // * Exile Zuko, then return him to the battlefield under an opponent's control. + ability.addMode(new Mode(new ZukoConflictedEffect()) + .addEffect(new LoseLifeSourceControllerEffect(2).setText(" control"))); + this.addAbility(ability); + } + + private ZukoConflicted(final ZukoConflicted card) { + super(card); + } + + @Override + public ZukoConflicted copy() { + return new ZukoConflicted(this); + } +} + +class ZukoConflictedEffect extends OneShotEffect { + + ZukoConflictedEffect() { + super(Outcome.Benefit); + staticText = "exile {this}, then return him to the battlefield under an opponent's"; + } + + private ZukoConflictedEffect(final ZukoConflictedEffect effect) { + super(effect); + } + + @Override + public ZukoConflictedEffect copy() { + return new ZukoConflictedEffect(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; + } + Card card = permanent.getMainCard(); + player.moveCards(permanent, Zone.EXILED, source, game); + TargetPlayer target = new TargetOpponent(true); + player.choose(outcome, target, source, game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent != null) { + opponent.moveCards(card, Zone.BATTLEFIELD, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZukoFirebendingMaster.java b/Mage.Sets/src/mage/cards/z/ZukoFirebendingMaster.java new file mode 100644 index 00000000000..38020b147b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukoFirebendingMaster.java @@ -0,0 +1,59 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsPhaseCondition; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersControllerCount; +import mage.abilities.effects.common.counter.AddCountersPlayersEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author anonymous + */ +public final class ZukoFirebendingMaster extends CardImpl { + + private static final DynamicValue xValue = new CountersControllerCount(CounterType.EXPERIENCE); + private static final Condition condition = new IsPhaseCondition(TurnPhase.COMBAT); + + public ZukoFirebendingMaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.subtype.add(SubType.ALLY); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Firebending X where X is the number of experience counters you have. + this.addAbility(new FirebendingAbility(xValue)); + + // Whenever you cast a spell during combat, you get an experience counter. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersPlayersEffect(CounterType.EXPERIENCE.createInstance(), TargetController.YOU), + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL + ).withTriggerCondition(condition)); + } + + private ZukoFirebendingMaster(final ZukoFirebendingMaster card) { + super(card); + } + + @Override + public ZukoFirebendingMaster copy() { + return new ZukoFirebendingMaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZukoSeekingHonor.java b/Mage.Sets/src/mage/cards/z/ZukoSeekingHonor.java new file mode 100644 index 00000000000..dd0899f43d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukoSeekingHonor.java @@ -0,0 +1,58 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.FirstStrikeAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZukoSeekingHonor extends CardImpl { + + public ZukoSeekingHonor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B/R}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Firebending 1 + this.addAbility(new FirebendingAbility(1)); + + // Whenever you cast a noncreature spell, Zuko gains first strike until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility( + new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + + // Whenever Zuko deals combat damage to a player, put a +1/+1 counter on him. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)).setText("put a +1/+1 counter on him") + )); + } + + private ZukoSeekingHonor(final ZukoSeekingHonor card) { + super(card); + } + + @Override + public ZukoSeekingHonor copy() { + return new ZukoSeekingHonor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZukosConviction.java b/Mage.Sets/src/mage/cards/z/ZukosConviction.java new file mode 100644 index 00000000000..33b248dca9f --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukosConviction.java @@ -0,0 +1,45 @@ +package mage.cards.z; + +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.keyword.KickerAbility; +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 ZukosConviction extends CardImpl { + + public ZukosConviction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); + + // Kicker {4} + this.addAbility(new KickerAbility("{4}")); + + // Return target creature card from your graveyard to your hand. If this spell was kicked, instead put that card onto the battlefield tapped. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new ReturnFromGraveyardToBattlefieldTargetEffect(true), + new ReturnFromGraveyardToHandTargetEffect(), + KickedCondition.ONCE, "return target creature card from your graveyard to your hand. " + + "If this spell was kicked, instead put that card onto the battlefield tapped" + )); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + } + + private ZukosConviction(final ZukosConviction card) { + super(card); + } + + @Override + public ZukosConviction copy() { + return new ZukosConviction(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZukosExile.java b/Mage.Sets/src/mage/cards/z/ZukosExile.java new file mode 100644 index 00000000000..baf5c4d75fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZukosExile.java @@ -0,0 +1,39 @@ +package mage.cards.z; + +import mage.abilities.effects.common.CreateTokenControllerTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +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.ClueArtifactToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZukosExile extends CardImpl { + + public ZukosExile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}"); + + this.subtype.add(SubType.LESSON); + + // Exile target artifact, creature, or enchantment. Its controller creates a Clue token. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addEffect(new CreateTokenControllerTargetEffect(new ClueArtifactToken())); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT)); + } + + private ZukosExile(final ZukosExile card) { + super(card); + } + + @Override + public ZukosExile copy() { + return new ZukosExile(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Alliances.java b/Mage.Sets/src/mage/sets/Alliances.java index 1509e7431c6..b01c236c242 100644 --- a/Mage.Sets/src/mage/sets/Alliances.java +++ b/Mage.Sets/src/mage/sets/Alliances.java @@ -158,6 +158,7 @@ public final class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Royal Herbalist", "15a", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Royal Herbalist", "15b", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Scarab of the Unseen", 128, Rarity.UNCOMMON, mage.cards.s.ScarabOfTheUnseen.class, RETRO_ART)); + cards.add(new SetCardInfo("Scars of the Veteran", 16, Rarity.UNCOMMON, mage.cards.s.ScarsOfTheVeteran.class, RETRO_ART)); cards.add(new SetCardInfo("School of the Unseen", 141, Rarity.UNCOMMON, mage.cards.s.SchoolOfTheUnseen.class, RETRO_ART)); cards.add(new SetCardInfo("Seasoned Tactician", 17, Rarity.UNCOMMON, mage.cards.s.SeasonedTactician.class, RETRO_ART)); cards.add(new SetCardInfo("Sheltered Valley", 142, Rarity.RARE, mage.cards.s.ShelteredValley.class, RETRO_ART)); diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java index 920084b6117..dd5e72509d3 100644 --- a/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbender.java @@ -12,7 +12,7 @@ import java.util.List; */ public final class AvatarTheLastAirbender extends ExpansionSet { - private static final List unfinished = Arrays.asList("Aang's Iceberg", "Avatar Aang", "Aang, Master of Elements", "Flexible Waterbender", "Geyser Leaper", "Giant Koi", "Katara, Bending Prodigy", "Katara, Water Tribe's Hope", "Waterbending Lesson", "Watery Grasp", "Yue, the Moon Spirit"); + private static final List unfinished = Arrays.asList("Aang's Iceberg", "Aang, Swift Savior", "Avatar Aang", "Benevolent River Spirit", "Crashing Wave", "Flexible Waterbender", "Foggy Swamp Vinebender", "Foggy Swamp Visions", "Geyser Leaper", "Giant Koi", "Hama, the Bloodbender", "Invasion Submersible", "Katara, Bending Prodigy", "Katara, Water Tribe's Hope", "North Pole Patrol", "Ruinous Waterbending", "Secret of Bloodbending", "Spirit Water Revival", "The Legend of Kuruk", "The Unagi of Kyoshi Island", "Waterbender Ascension", "Waterbending Lesson", "Water Tribe Rallier", "Watery Grasp", "Yue, the Moon Spirit"); private static final AvatarTheLastAirbender instance = new AvatarTheLastAirbender(); public static AvatarTheLastAirbender getInstance() { @@ -25,119 +25,400 @@ public final class AvatarTheLastAirbender extends ExpansionSet { this.rotationSet = true; this.hasBasicLands = true; + this.enablePlayBooster(Integer.MAX_VALUE); + this.numBoosterDoubleFaced = -1; + cards.add(new SetCardInfo("Aang's Iceberg", 336, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Iceberg", 5, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Journey", 1, Rarity.COMMON, mage.cards.a.AangsJourney.class)); - cards.add(new SetCardInfo("Aang, Master of Elements", 207, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Master of Elements", 363, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, Swift Savior", 204, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, Swift Savior", 298, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, Swift Savior", 347, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, Swift Savior", 359, Rarity.RARE, mage.cards.a.AangSwiftSavior.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, at the Crossroads", 203, Rarity.RARE, mage.cards.a.AangAtTheCrossroads.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, at the Crossroads", 304, Rarity.RARE, mage.cards.a.AangAtTheCrossroads.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, at the Crossroads", 346, Rarity.RARE, mage.cards.a.AangAtTheCrossroads.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, the Last Airbender", 4, Rarity.UNCOMMON, mage.cards.a.AangTheLastAirbender.class)); cards.add(new SetCardInfo("Abandon Attachments", 205, Rarity.COMMON, mage.cards.a.AbandonAttachments.class)); + cards.add(new SetCardInfo("Abandoned Air Temple", 263, Rarity.RARE, mage.cards.a.AbandonedAirTemple.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Abandoned Air Temple", 386, Rarity.RARE, mage.cards.a.AbandonedAirTemple.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Accumulate Wisdom", 44, Rarity.UNCOMMON, mage.cards.a.AccumulateWisdom.class)); + cards.add(new SetCardInfo("Agna Qel'a", 264, Rarity.RARE, mage.cards.a.AgnaQela.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Agna Qel'a", 387, Rarity.RARE, mage.cards.a.AgnaQela.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Air Nomad Legacy", 206, Rarity.UNCOMMON, mage.cards.a.AirNomadLegacy.class)); + cards.add(new SetCardInfo("Airbender Ascension", 364, Rarity.RARE, mage.cards.a.AirbenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Airbender Ascension", 6, Rarity.RARE, mage.cards.a.AirbenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Airbender's Reversal", 7, Rarity.UNCOMMON, mage.cards.a.AirbendersReversal.class)); cards.add(new SetCardInfo("Airbending Lesson", 8, Rarity.COMMON, mage.cards.a.AirbendingLesson.class)); + cards.add(new SetCardInfo("Airship Engine Room", 265, Rarity.COMMON, mage.cards.a.AirshipEngineRoom.class)); + cards.add(new SetCardInfo("Allies at Last", 164, Rarity.UNCOMMON, mage.cards.a.AlliesAtLast.class)); + cards.add(new SetCardInfo("Appa, Loyal Sky Bison", 9, Rarity.UNCOMMON, mage.cards.a.AppaLoyalSkyBison.class)); cards.add(new SetCardInfo("Appa, Steadfast Guardian", 10, Rarity.MYTHIC, mage.cards.a.AppaSteadfastGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Appa, Steadfast Guardian", 316, Rarity.MYTHIC, mage.cards.a.AppaSteadfastGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Aang", 207, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Aang", 308, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Aang", 363, Rarity.MYTHIC, mage.cards.a.AvatarAang.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Destiny", 165, Rarity.RARE, mage.cards.a.AvatarDestiny.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar Destiny", 333, Rarity.RARE, mage.cards.a.AvatarDestiny.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avatar Enthusiasts", 11, Rarity.COMMON, mage.cards.a.AvatarEnthusiasts.class)); + cards.add(new SetCardInfo("Avatar's Wrath", 12, Rarity.RARE, mage.cards.a.AvatarsWrath.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Avatar's Wrath", 365, Rarity.RARE, mage.cards.a.AvatarsWrath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Azula Always Lies", 84, Rarity.COMMON, mage.cards.a.AzulaAlwaysLies.class)); + cards.add(new SetCardInfo("Azula, Cunning Usurper", 208, Rarity.RARE, mage.cards.a.AzulaCunningUsurper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azula, Cunning Usurper", 303, Rarity.RARE, mage.cards.a.AzulaCunningUsurper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azula, On the Hunt", 85, Rarity.UNCOMMON, mage.cards.a.AzulaOnTheHunt.class)); + cards.add(new SetCardInfo("Ba Sing Se", 266, Rarity.RARE, mage.cards.b.BaSingSe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ba Sing Se", 388, Rarity.RARE, mage.cards.b.BaSingSe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Badgermole Cub", 167, Rarity.MYTHIC, mage.cards.b.BadgermoleCub.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Badgermole Cub", 326, Rarity.MYTHIC, mage.cards.b.BadgermoleCub.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Badgermole", 166, Rarity.COMMON, mage.cards.b.Badgermole.class)); cards.add(new SetCardInfo("Barrels of Blasting Jelly", 254, Rarity.COMMON, mage.cards.b.BarrelsOfBlastingJelly.class)); cards.add(new SetCardInfo("Beetle-Headed Merchants", 86, Rarity.COMMON, mage.cards.b.BeetleHeadedMerchants.class)); + cards.add(new SetCardInfo("Beifong's Bounty Hunters", 209, Rarity.RARE, mage.cards.b.BeifongsBountyHunters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Beifong's Bounty Hunters", 379, Rarity.RARE, mage.cards.b.BeifongsBountyHunters.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bender's Waterskin", 255, Rarity.COMMON, mage.cards.b.BendersWaterskin.class)); + cards.add(new SetCardInfo("Benevolent River Spirit", 45, Rarity.UNCOMMON, mage.cards.b.BenevolentRiverSpirit.class)); + cards.add(new SetCardInfo("Bitter Work", 210, Rarity.UNCOMMON, mage.cards.b.BitterWork.class)); + cards.add(new SetCardInfo("Boar-q-pine", 124, Rarity.COMMON, mage.cards.b.BoarQPine.class)); + cards.add(new SetCardInfo("Boiling Rock Prison", 267, Rarity.COMMON, mage.cards.b.BoilingRockPrison.class)); + cards.add(new SetCardInfo("Boiling Rock Rioter", 372, Rarity.RARE, mage.cards.b.BoilingRockRioter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Boiling Rock Rioter", 87, Rarity.RARE, mage.cards.b.BoilingRockRioter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Boomerang Basics", 46, Rarity.UNCOMMON, mage.cards.b.BoomerangBasics.class)); + cards.add(new SetCardInfo("Bumi Bash", 125, Rarity.COMMON, mage.cards.b.BumiBash.class)); + cards.add(new SetCardInfo("Bumi, King of Three Trials", 169, Rarity.UNCOMMON, mage.cards.b.BumiKingOfThreeTrials.class)); + cards.add(new SetCardInfo("Bumi, Unleashed", 211, Rarity.MYTHIC, mage.cards.b.BumiUnleashed.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bumi, Unleashed", 348, Rarity.MYTHIC, mage.cards.b.BumiUnleashed.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Buzzard-Wasp Colony", 88, Rarity.UNCOMMON, mage.cards.b.BuzzardWaspColony.class)); + cards.add(new SetCardInfo("Callous Inspector", 89, Rarity.COMMON, mage.cards.c.CallousInspector.class)); + cards.add(new SetCardInfo("Canyon Crawler", 90, Rarity.COMMON, mage.cards.c.CanyonCrawler.class)); cards.add(new SetCardInfo("Cat-Gator", 91, Rarity.UNCOMMON, mage.cards.c.CatGator.class)); cards.add(new SetCardInfo("Cat-Owl", 212, Rarity.COMMON, mage.cards.c.CatOwl.class)); + cards.add(new SetCardInfo("Combustion Man", 127, Rarity.UNCOMMON, mage.cards.c.CombustionMan.class)); + cards.add(new SetCardInfo("Combustion Technique", 128, Rarity.UNCOMMON, mage.cards.c.CombustionTechnique.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Combustion Technique", 301, Rarity.UNCOMMON, mage.cards.c.CombustionTechnique.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Compassionate Healer", 13, Rarity.COMMON, mage.cards.c.CompassionateHealer.class)); cards.add(new SetCardInfo("Corrupt Court Official", 92, Rarity.COMMON, mage.cards.c.CorruptCourtOfficial.class)); + cards.add(new SetCardInfo("Crashing Wave", 300, Rarity.UNCOMMON, mage.cards.c.CrashingWave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crashing Wave", 47, Rarity.UNCOMMON, mage.cards.c.CrashingWave.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crescent Island Temple", 129, Rarity.UNCOMMON, mage.cards.c.CrescentIslandTemple.class)); + cards.add(new SetCardInfo("Cruel Administrator", 213, Rarity.UNCOMMON, mage.cards.c.CruelAdministrator.class)); + cards.add(new SetCardInfo("Cunning Maneuver", 130, Rarity.COMMON, mage.cards.c.CunningManeuver.class)); + cards.add(new SetCardInfo("Curious Farm Animals", 14, Rarity.COMMON, mage.cards.c.CuriousFarmAnimals.class)); + cards.add(new SetCardInfo("Cycle of Renewal", 170, Rarity.COMMON, mage.cards.c.CycleOfRenewal.class)); + cards.add(new SetCardInfo("Dai Li Agents", 214, Rarity.UNCOMMON, mage.cards.d.DaiLiAgents.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dai Li Agents", 306, Rarity.UNCOMMON, mage.cards.d.DaiLiAgents.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dai Li Indoctrination", 93, Rarity.COMMON, mage.cards.d.DaiLiIndoctrination.class)); + cards.add(new SetCardInfo("Day of Black Sun", 373, Rarity.RARE, mage.cards.d.DayOfBlackSun.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Day of Black Sun", 94, Rarity.RARE, mage.cards.d.DayOfBlackSun.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Deadly Precision", 95, Rarity.COMMON, mage.cards.d.DeadlyPrecision.class)); cards.add(new SetCardInfo("Deserter's Disciple", 131, Rarity.COMMON, mage.cards.d.DesertersDisciple.class)); + cards.add(new SetCardInfo("Destined Confrontation", 15, Rarity.UNCOMMON, mage.cards.d.DestinedConfrontation.class)); + cards.add(new SetCardInfo("Diligent Zookeeper", 171, Rarity.RARE, mage.cards.d.DiligentZookeeper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Diligent Zookeeper", 327, Rarity.RARE, mage.cards.d.DiligentZookeeper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dragonfly Swarm", 215, Rarity.UNCOMMON, mage.cards.d.DragonflySwarm.class)); + cards.add(new SetCardInfo("Earth King's Lieutenant", 217, Rarity.RARE, mage.cards.e.EarthKingsLieutenant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Earth King's Lieutenant", 380, Rarity.RARE, mage.cards.e.EarthKingsLieutenant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Earth Kingdom General", 173, Rarity.UNCOMMON, mage.cards.e.EarthKingdomGeneral.class)); + cards.add(new SetCardInfo("Earth Kingdom Jailer", 16, Rarity.UNCOMMON, mage.cards.e.EarthKingdomJailer.class)); + cards.add(new SetCardInfo("Earth Kingdom Protectors", 17, Rarity.UNCOMMON, mage.cards.e.EarthKingdomProtectors.class)); cards.add(new SetCardInfo("Earth Kingdom Soldier", 216, Rarity.COMMON, mage.cards.e.EarthKingdomSoldier.class)); + cards.add(new SetCardInfo("Earth Rumble Wrestlers", 218, Rarity.COMMON, mage.cards.e.EarthRumbleWrestlers.class)); cards.add(new SetCardInfo("Earth Rumble", 174, Rarity.UNCOMMON, mage.cards.e.EarthRumble.class)); cards.add(new SetCardInfo("Earth Village Ruffians", 219, Rarity.COMMON, mage.cards.e.EarthVillageRuffians.class)); + cards.add(new SetCardInfo("Earthbender Ascension", 175, Rarity.RARE, mage.cards.e.EarthbenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Earthbender Ascension", 307, Rarity.RARE, mage.cards.e.EarthbenderAscension.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Earthbending Lesson", 176, Rarity.COMMON, mage.cards.e.EarthbendingLesson.class)); + cards.add(new SetCardInfo("Earthen Ally", 177, Rarity.RARE, mage.cards.e.EarthenAlly.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Earthen Ally", 377, Rarity.RARE, mage.cards.e.EarthenAlly.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elemental Teachings", 178, Rarity.RARE, mage.cards.e.ElementalTeachings.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elemental Teachings", 378, Rarity.RARE, mage.cards.e.ElementalTeachings.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ember Island Production", 48, Rarity.UNCOMMON, mage.cards.e.EmberIslandProduction.class)); + cards.add(new SetCardInfo("Energybending", 2, Rarity.UNCOMMON, mage.cards.e.Energybending.class)); + cards.add(new SetCardInfo("Enter the Avatar State", 18, Rarity.UNCOMMON, mage.cards.e.EnterTheAvatarState.class)); cards.add(new SetCardInfo("Epic Downfall", 96, Rarity.UNCOMMON, mage.cards.e.EpicDownfall.class)); + cards.add(new SetCardInfo("Fancy Footwork", 19, Rarity.UNCOMMON, mage.cards.f.FancyFootwork.class)); + cards.add(new SetCardInfo("Fatal Fissure", 97, Rarity.UNCOMMON, mage.cards.f.FatalFissure.class)); cards.add(new SetCardInfo("Fated Firepower", 132, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fated Firepower", 297, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fated Firepower", 341, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fire Lord Sozin", 117, Rarity.MYTHIC, mage.cards.f.FireLordSozin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fire Lord Sozin", 356, Rarity.MYTHIC, mage.cards.f.FireLordSozin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Azula", 220, Rarity.RARE, mage.cards.f.FireLordAzula.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Azula", 313, Rarity.RARE, mage.cards.f.FireLordAzula.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Azula", 334, Rarity.RARE, mage.cards.f.FireLordAzula.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Lord Zuko", 221, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fire Lord Zuko", 360, Rarity.RARE, mage.cards.f.FireLordZuko.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class)); + cards.add(new SetCardInfo("Fire Lord Zuko", 315, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Zuko", 360, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Attacks", 299, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Cadets", 134, Rarity.COMMON, mage.cards.f.FireNationCadets.class)); cards.add(new SetCardInfo("Fire Nation Engineer", 99, Rarity.UNCOMMON, mage.cards.f.FireNationEngineer.class)); + cards.add(new SetCardInfo("Fire Nation Palace", 268, Rarity.RARE, mage.cards.f.FireNationPalace.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Palace", 389, Rarity.RARE, mage.cards.f.FireNationPalace.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Raider", 135, Rarity.COMMON, mage.cards.f.FireNationRaider.class)); + cards.add(new SetCardInfo("Fire Nation Warship", 256, Rarity.UNCOMMON, mage.cards.f.FireNationWarship.class)); + cards.add(new SetCardInfo("Fire Navy Trebuchet", 100, Rarity.UNCOMMON, mage.cards.f.FireNavyTrebuchet.class)); cards.add(new SetCardInfo("Fire Sages", 136, Rarity.UNCOMMON, mage.cards.f.FireSages.class)); + cards.add(new SetCardInfo("Firebender Ascension", 137, Rarity.RARE, mage.cards.f.FirebenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Firebender Ascension", 312, Rarity.RARE, mage.cards.f.FirebenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Firebending Lesson", 138, Rarity.COMMON, mage.cards.f.FirebendingLesson.class)); + cards.add(new SetCardInfo("Firebending Student", 139, Rarity.RARE, mage.cards.f.FirebendingStudent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Firebending Student", 342, Rarity.RARE, mage.cards.f.FirebendingStudent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Firebending Student", 393, Rarity.RARE, mage.cards.f.FirebendingStudent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("First-Time Flyer", 49, Rarity.COMMON, mage.cards.f.FirstTimeFlyer.class)); cards.add(new SetCardInfo("Flexible Waterbender", 50, Rarity.COMMON, mage.cards.f.FlexibleWaterbender.class)); cards.add(new SetCardInfo("Flopsie, Bumi's Buddy", 179, Rarity.UNCOMMON, mage.cards.f.FlopsieBumisBuddy.class)); + cards.add(new SetCardInfo("Foggy Bottom Swamp", 269, Rarity.COMMON, mage.cards.f.FoggyBottomSwamp.class)); + cards.add(new SetCardInfo("Foggy Swamp Hunters", 101, Rarity.COMMON, mage.cards.f.FoggySwampHunters.class)); + cards.add(new SetCardInfo("Foggy Swamp Spirit Keeper", 222, Rarity.UNCOMMON, mage.cards.f.FoggySwampSpiritKeeper.class)); + cards.add(new SetCardInfo("Foggy Swamp Vinebender", 180, Rarity.COMMON, mage.cards.f.FoggySwampVinebender.class)); + cards.add(new SetCardInfo("Foggy Swamp Visions", 102, Rarity.RARE, mage.cards.f.FoggySwampVisions.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foggy Swamp Visions", 339, Rarity.RARE, mage.cards.f.FoggySwampVisions.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forecasting Fortune Teller", 51, Rarity.COMMON, mage.cards.f.ForecastingFortuneTeller.class)); cards.add(new SetCardInfo("Forest", 286, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 296, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Gather the White Lotus", 20, Rarity.UNCOMMON, mage.cards.g.GatherTheWhiteLotus.class)); cards.add(new SetCardInfo("Geyser Leaper", 52, Rarity.COMMON, mage.cards.g.GeyserLeaper.class)); cards.add(new SetCardInfo("Giant Koi", 53, Rarity.COMMON, mage.cards.g.GiantKoi.class)); cards.add(new SetCardInfo("Glider Kids", 21, Rarity.COMMON, mage.cards.g.GliderKids.class)); - cards.add(new SetCardInfo("Hakoda, Selfless Commander", 366, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class)); + cards.add(new SetCardInfo("Glider Staff", 22, Rarity.UNCOMMON, mage.cards.g.GliderStaff.class)); + cards.add(new SetCardInfo("Gran-Gran", 54, Rarity.UNCOMMON, mage.cards.g.GranGran.class)); + cards.add(new SetCardInfo("Great Divide Guide", 181, Rarity.RARE, mage.cards.g.GreatDivideGuide.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Great Divide Guide", 345, Rarity.RARE, mage.cards.g.GreatDivideGuide.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Guru Pathik", 223, Rarity.UNCOMMON, mage.cards.g.GuruPathik.class)); + cards.add(new SetCardInfo("Hakoda, Selfless Commander", 23, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hakoda, Selfless Commander", 366, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hama, the Bloodbender", 224, Rarity.UNCOMMON, mage.cards.h.HamaTheBloodbender.class)); cards.add(new SetCardInfo("Haru, Hidden Talent", 182, Rarity.UNCOMMON, mage.cards.h.HaruHiddenTalent.class)); cards.add(new SetCardInfo("Heartless Act", 103, Rarity.UNCOMMON, mage.cards.h.HeartlessAct.class)); cards.add(new SetCardInfo("Hei Bai, Spirit of Balance", 225, Rarity.UNCOMMON, mage.cards.h.HeiBaiSpiritOfBalance.class)); + cards.add(new SetCardInfo("Hermitic Herbalist", 226, Rarity.UNCOMMON, mage.cards.h.HermiticHerbalist.class)); cards.add(new SetCardInfo("Hog-Monkey", 104, Rarity.COMMON, mage.cards.h.HogMonkey.class)); + cards.add(new SetCardInfo("Honest Work", 55, Rarity.UNCOMMON, mage.cards.h.HonestWork.class)); cards.add(new SetCardInfo("How to Start a Riot", 140, Rarity.COMMON, mage.cards.h.HowToStartARiot.class)); cards.add(new SetCardInfo("Iguana Parrot", 56, Rarity.COMMON, mage.cards.i.IguanaParrot.class)); + cards.add(new SetCardInfo("Invasion Reinforcements", 24, Rarity.UNCOMMON, mage.cards.i.InvasionReinforcements.class)); + cards.add(new SetCardInfo("Invasion Submersible", 57, Rarity.UNCOMMON, mage.cards.i.InvasionSubmersible.class)); + cards.add(new SetCardInfo("Invasion Tactics", 183, Rarity.UNCOMMON, mage.cards.i.InvasionTactics.class)); + cards.add(new SetCardInfo("Iroh's Demonstration", 141, Rarity.UNCOMMON, mage.cards.i.IrohsDemonstration.class)); + cards.add(new SetCardInfo("Iroh, Grand Lotus", 227, Rarity.RARE, mage.cards.i.IrohGrandLotus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Grand Lotus", 349, Rarity.RARE, mage.cards.i.IrohGrandLotus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Tea Master", 228, Rarity.RARE, mage.cards.i.IrohTeaMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Tea Master", 381, Rarity.RARE, mage.cards.i.IrohTeaMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 283, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 293, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("It'll Quench Ya!", 58, Rarity.COMMON, mage.cards.i.ItllQuenchYa.class)); + cards.add(new SetCardInfo("Jasmine Dragon Tea Shop", 270, Rarity.RARE, mage.cards.j.JasmineDragonTeaShop.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jasmine Dragon Tea Shop", 390, Rarity.RARE, mage.cards.j.JasmineDragonTeaShop.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jeong Jeong's Deserters", 25, Rarity.COMMON, mage.cards.j.JeongJeongsDeserters.class)); + cards.add(new SetCardInfo("Jeong Jeong, the Deserter", 142, Rarity.UNCOMMON, mage.cards.j.JeongJeongTheDeserter.class)); + cards.add(new SetCardInfo("Jet's Brainwashing", 143, Rarity.UNCOMMON, mage.cards.j.JetsBrainwashing.class)); + cards.add(new SetCardInfo("Jet, Freedom Fighter", 229, Rarity.UNCOMMON, mage.cards.j.JetFreedomFighter.class)); + cards.add(new SetCardInfo("Joo Dee, One of Many", 105, Rarity.UNCOMMON, mage.cards.j.JooDeeOneOfMany.class)); + cards.add(new SetCardInfo("June, Bounty Hunter", 106, Rarity.UNCOMMON, mage.cards.j.JuneBountyHunter.class)); cards.add(new SetCardInfo("Katara, Bending Prodigy", 59, Rarity.UNCOMMON, mage.cards.k.KataraBendingProdigy.class)); cards.add(new SetCardInfo("Katara, Water Tribe's Hope", 231, Rarity.RARE, mage.cards.k.KataraWaterTribesHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, Water Tribe's Hope", 351, Rarity.RARE, mage.cards.k.KataraWaterTribesHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, the Fearless", 230, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Katara, the Fearless", 305, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, the Fearless", 350, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Katara, the Fearless", 361, Rarity.RARE, mage.cards.k.KataraTheFearless.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Katara, the Fearless", 361, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Knowledge Seeker", 60, Rarity.UNCOMMON, mage.cards.k.KnowledgeSeeker.class)); + cards.add(new SetCardInfo("Koh, the Face Stealer", 107, Rarity.MYTHIC, mage.cards.k.KohTheFaceStealer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Koh, the Face Stealer", 322, Rarity.MYTHIC, mage.cards.k.KohTheFaceStealer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kyoshi Battle Fan", 257, Rarity.COMMON, mage.cards.k.KyoshiBattleFan.class)); + cards.add(new SetCardInfo("Kyoshi Island Plaza", 184, Rarity.UNCOMMON, mage.cards.k.KyoshiIslandPlaza.class)); + cards.add(new SetCardInfo("Kyoshi Village", 271, Rarity.COMMON, mage.cards.k.KyoshiVillage.class)); + cards.add(new SetCardInfo("Kyoshi Warriors", 26, Rarity.COMMON, mage.cards.k.KyoshiWarriors.class)); + cards.add(new SetCardInfo("Leaves from the Vine", 185, Rarity.UNCOMMON, mage.cards.l.LeavesFromTheVine.class)); cards.add(new SetCardInfo("Lightning Strike", 146, Rarity.COMMON, mage.cards.l.LightningStrike.class)); + cards.add(new SetCardInfo("Lo and Li, Twin Tutors", 108, Rarity.UNCOMMON, mage.cards.l.LoAndLiTwinTutors.class)); cards.add(new SetCardInfo("Long Feng, Grand Secretariat", 233, Rarity.UNCOMMON, mage.cards.l.LongFengGrandSecretariat.class)); + cards.add(new SetCardInfo("Lost Days", 62, Rarity.COMMON, mage.cards.l.LostDays.class)); + cards.add(new SetCardInfo("Mai, Jaded Edge", 147, Rarity.UNCOMMON, mage.cards.m.MaiJadedEdge.class)); + cards.add(new SetCardInfo("Mai, Scornful Striker", 109, Rarity.RARE, mage.cards.m.MaiScornfulStriker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mai, Scornful Striker", 374, Rarity.RARE, mage.cards.m.MaiScornfulStriker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Master Pakku", 63, Rarity.UNCOMMON, mage.cards.m.MasterPakku.class)); cards.add(new SetCardInfo("Master Piandao", 28, Rarity.UNCOMMON, mage.cards.m.MasterPiandao.class)); + cards.add(new SetCardInfo("Meditation Pools", 272, Rarity.COMMON, mage.cards.m.MeditationPools.class)); cards.add(new SetCardInfo("Merchant of Many Hats", 110, Rarity.COMMON, mage.cards.m.MerchantOfManyHats.class)); + cards.add(new SetCardInfo("Messenger Hawk", 234, Rarity.COMMON, mage.cards.m.MessengerHawk.class)); + cards.add(new SetCardInfo("Meteor Sword", 258, Rarity.UNCOMMON, mage.cards.m.MeteorSword.class)); + cards.add(new SetCardInfo("Misty Palms Oasis", 273, Rarity.COMMON, mage.cards.m.MistyPalmsOasis.class)); cards.add(new SetCardInfo("Momo, Friendly Flier", 29, Rarity.RARE, mage.cards.m.MomoFriendlyFlier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Momo, Friendly Flier", 317, Rarity.RARE, mage.cards.m.MomoFriendlyFlier.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Momo, Friendly Flier", 394, Rarity.RARE, mage.cards.m.MomoFriendlyFlier.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Momo, Playful Pet", 30, Rarity.UNCOMMON, mage.cards.m.MomoPlayfulPet.class)); cards.add(new SetCardInfo("Mongoose Lizard", 148, Rarity.COMMON, mage.cards.m.MongooseLizard.class)); cards.add(new SetCardInfo("Mountain", 285, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 295, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("North Pole Gates", 274, Rarity.COMMON, mage.cards.n.NorthPoleGates.class)); + cards.add(new SetCardInfo("North Pole Patrol", 65, Rarity.UNCOMMON, mage.cards.n.NorthPolePatrol.class)); + cards.add(new SetCardInfo("Northern Air Temple", 111, Rarity.UNCOMMON, mage.cards.n.NorthernAirTemple.class)); + cards.add(new SetCardInfo("Obsessive Pursuit", 112, Rarity.RARE, mage.cards.o.ObsessivePursuit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obsessive Pursuit", 340, Rarity.RARE, mage.cards.o.ObsessivePursuit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Octopus Form", 66, Rarity.COMMON, mage.cards.o.OctopusForm.class)); + cards.add(new SetCardInfo("Omashu City", 275, Rarity.COMMON, mage.cards.o.OmashuCity.class)); + cards.add(new SetCardInfo("Origin of Metalbending", 187, Rarity.COMMON, mage.cards.o.OriginOfMetalbending.class)); cards.add(new SetCardInfo("Ostrich-Horse", 188, Rarity.COMMON, mage.cards.o.OstrichHorse.class)); cards.add(new SetCardInfo("Otter-Penguin", 67, Rarity.COMMON, mage.cards.o.OtterPenguin.class)); cards.add(new SetCardInfo("Ozai's Cruelty", 113, Rarity.UNCOMMON, mage.cards.o.OzaisCruelty.class)); + cards.add(new SetCardInfo("Ozai, the Phoenix King", 235, Rarity.MYTHIC, mage.cards.o.OzaiThePhoenixKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ozai, the Phoenix King", 311, Rarity.MYTHIC, mage.cards.o.OzaiThePhoenixKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ozai, the Phoenix King", 335, Rarity.MYTHIC, mage.cards.o.OzaiThePhoenixKing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Path to Redemption", 31, Rarity.COMMON, mage.cards.p.PathToRedemption.class)); + cards.add(new SetCardInfo("Phoenix Fleet Airship", 114, Rarity.MYTHIC, mage.cards.p.PhoenixFleetAirship.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phoenix Fleet Airship", 323, Rarity.MYTHIC, mage.cards.p.PhoenixFleetAirship.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pillar Launch", 189, Rarity.COMMON, mage.cards.p.PillarLaunch.class)); + cards.add(new SetCardInfo("Pirate Peddlers", 115, Rarity.COMMON, mage.cards.p.PiratePeddlers.class)); cards.add(new SetCardInfo("Plains", 282, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 287, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 292, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Planetarium of Wan Shi Tong", 259, Rarity.MYTHIC, mage.cards.p.PlanetariumOfWanShiTong.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Planetarium of Wan Shi Tong", 385, Rarity.MYTHIC, mage.cards.p.PlanetariumOfWanShiTong.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Platypus-Bear", 236, Rarity.COMMON, mage.cards.p.PlatypusBear.class)); cards.add(new SetCardInfo("Pretending Poxbearers", 237, Rarity.COMMON, mage.cards.p.PretendingPoxbearers.class)); + cards.add(new SetCardInfo("Price of Freedom", 149, Rarity.UNCOMMON, mage.cards.p.PriceOfFreedom.class)); + cards.add(new SetCardInfo("Professor Zei, Anthropologist", 238, Rarity.UNCOMMON, mage.cards.p.ProfessorZeiAnthropologist.class)); cards.add(new SetCardInfo("Rabaroo Troop", 32, Rarity.COMMON, mage.cards.r.RabarooTroop.class)); + cards.add(new SetCardInfo("Ran and Shaw", 150, Rarity.RARE, mage.cards.r.RanAndShaw.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ran and Shaw", 325, Rarity.RARE, mage.cards.r.RanAndShaw.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Raucous Audience", 190, Rarity.COMMON, mage.cards.r.RaucousAudience.class)); + cards.add(new SetCardInfo("Raven Eagle", 116, Rarity.RARE, mage.cards.r.RavenEagle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raven Eagle", 324, Rarity.RARE, mage.cards.r.RavenEagle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Razor Rings", 33, Rarity.COMMON, mage.cards.r.RazorRings.class)); + cards.add(new SetCardInfo("Realm of Koh", 276, Rarity.RARE, mage.cards.r.RealmOfKoh.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Realm of Koh", 391, Rarity.RARE, mage.cards.r.RealmOfKoh.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rebellious Captives", 191, Rarity.COMMON, mage.cards.r.RebelliousCaptives.class)); cards.add(new SetCardInfo("Redirect Lightning", 151, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Redirect Lightning", 343, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rockalanche", 192, Rarity.UNCOMMON, mage.cards.r.Rockalanche.class)); cards.add(new SetCardInfo("Rocky Rebuke", 193, Rarity.COMMON, mage.cards.r.RockyRebuke.class)); cards.add(new SetCardInfo("Rough Rhino Cavalry", 152, Rarity.COMMON, mage.cards.r.RoughRhinoCavalry.class)); cards.add(new SetCardInfo("Rowdy Snowballers", 68, Rarity.COMMON, mage.cards.r.RowdySnowballers.class)); + cards.add(new SetCardInfo("Ruinous Waterbending", 118, Rarity.UNCOMMON, mage.cards.r.RuinousWaterbending.class)); + cards.add(new SetCardInfo("Rumble Arena", 277, Rarity.COMMON, mage.cards.r.RumbleArena.class)); cards.add(new SetCardInfo("Saber-Tooth Moose-Lion", 194, Rarity.COMMON, mage.cards.s.SaberToothMooseLion.class)); + cards.add(new SetCardInfo("Sandbender Scavengers", 239, Rarity.RARE, mage.cards.s.SandbenderScavengers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sandbender Scavengers", 382, Rarity.RARE, mage.cards.s.SandbenderScavengers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sandbenders' Storm", 34, Rarity.COMMON, mage.cards.s.SandbendersStorm.class)); + cards.add(new SetCardInfo("Secret Tunnel", 278, Rarity.RARE, mage.cards.s.SecretTunnel.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Secret Tunnel", 392, Rarity.RARE, mage.cards.s.SecretTunnel.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Seismic Sense", 195, Rarity.UNCOMMON, mage.cards.s.SeismicSense.class)); cards.add(new SetCardInfo("Serpent of the Pass", 70, Rarity.UNCOMMON, mage.cards.s.SerpentOfThePass.class)); + cards.add(new SetCardInfo("Serpent's Pass", 279, Rarity.COMMON, mage.cards.s.SerpentsPass.class)); + cards.add(new SetCardInfo("Shared Roots", 196, Rarity.UNCOMMON, mage.cards.s.SharedRoots.class)); cards.add(new SetCardInfo("Sokka's Haiku", 71, Rarity.UNCOMMON, mage.cards.s.SokkasHaiku.class)); cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 240, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 383, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Lateral Strategist", 241, Rarity.UNCOMMON, mage.cards.s.SokkaLateralStrategist.class)); + cards.add(new SetCardInfo("Sokka, Tenacious Tactician", 242, Rarity.RARE, mage.cards.s.SokkaTenaciousTactician.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokka, Tenacious Tactician", 352, Rarity.RARE, mage.cards.s.SokkaTenaciousTactician.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sold Out", 119, Rarity.COMMON, mage.cards.s.SoldOut.class)); + cards.add(new SetCardInfo("Solstice Revelations", 153, Rarity.UNCOMMON, mage.cards.s.SolsticeRevelations.class)); + cards.add(new SetCardInfo("South Pole Voyager", 35, Rarity.RARE, mage.cards.s.SouthPoleVoyager.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("South Pole Voyager", 367, Rarity.RARE, mage.cards.s.SouthPoleVoyager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Southern Air Temple", 36, Rarity.UNCOMMON, mage.cards.s.SouthernAirTemple.class)); + cards.add(new SetCardInfo("Sozin's Comet", 154, Rarity.MYTHIC, mage.cards.s.SozinsComet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sozin's Comet", 309, Rarity.MYTHIC, mage.cards.s.SozinsComet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sozin's Comet", 332, Rarity.MYTHIC, mage.cards.s.SozinsComet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sparring Dummy", 197, Rarity.UNCOMMON, mage.cards.s.SparringDummy.class)); + cards.add(new SetCardInfo("Spirit Water Revival", 370, Rarity.RARE, mage.cards.s.SpiritWaterRevival.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirit Water Revival", 73, Rarity.RARE, mage.cards.s.SpiritWaterRevival.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suki, Courageous Rescuer", 368, Rarity.RARE, mage.cards.s.SukiCourageousRescuer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suki, Courageous Rescuer", 37, Rarity.RARE, mage.cards.s.SukiCourageousRescuer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suki, Kyoshi Warrior", 243, Rarity.UNCOMMON, mage.cards.s.SukiKyoshiWarrior.class)); + cards.add(new SetCardInfo("Sun Warriors", 244, Rarity.UNCOMMON, mage.cards.s.SunWarriors.class)); + cards.add(new SetCardInfo("Sun-Blessed Peak", 280, Rarity.COMMON, mage.cards.s.SunBlessedPeak.class)); cards.add(new SetCardInfo("Swamp", 284, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 289, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 294, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swampsnare Trap", 120, Rarity.COMMON, mage.cards.s.SwampsnareTrap.class)); + cards.add(new SetCardInfo("Team Avatar", 38, Rarity.UNCOMMON, mage.cards.t.TeamAvatar.class)); + cards.add(new SetCardInfo("Teo, Spirited Glider", 74, Rarity.UNCOMMON, mage.cards.t.TeoSpiritedGlider.class)); + cards.add(new SetCardInfo("The Boulder, Ready to Rumble", 168, Rarity.UNCOMMON, mage.cards.t.TheBoulderReadyToRumble.class)); + cards.add(new SetCardInfo("The Cave of Two Lovers", 126, Rarity.UNCOMMON, mage.cards.t.TheCaveOfTwoLovers.class)); + cards.add(new SetCardInfo("The Earth King", 172, Rarity.RARE, mage.cards.t.TheEarthKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Earth King", 344, Rarity.RARE, mage.cards.t.TheEarthKing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Fire Nation Drill", 321, Rarity.RARE, mage.cards.t.TheFireNationDrill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Fire Nation Drill", 98, Rarity.RARE, mage.cards.t.TheFireNationDrill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Last Agni Kai", 144, Rarity.RARE, mage.cards.t.TheLastAgniKai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Last Agni Kai", 314, Rarity.RARE, mage.cards.t.TheLastAgniKai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Kuruk", 355, Rarity.MYTHIC, mage.cards.t.TheLegendOfKuruk.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Kuruk", 61, Rarity.MYTHIC, mage.cards.t.TheLegendOfKuruk.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Kyoshi", 186, Rarity.MYTHIC, mage.cards.t.TheLegendOfKyoshi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Kyoshi", 358, Rarity.MYTHIC, mage.cards.t.TheLegendOfKyoshi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Roku", 145, Rarity.MYTHIC, mage.cards.t.TheLegendOfRoku.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Roku", 357, Rarity.MYTHIC, mage.cards.t.TheLegendOfRoku.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Yangchen", 27, Rarity.MYTHIC, mage.cards.t.TheLegendOfYangchen.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Legend of Yangchen", 354, Rarity.MYTHIC, mage.cards.t.TheLegendOfYangchen.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Lion-Turtle", 232, Rarity.RARE, mage.cards.t.TheLionTurtle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Lion-Turtle", 328, Rarity.RARE, mage.cards.t.TheLionTurtle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Mechanist, Aerial Artisan", 369, Rarity.RARE, mage.cards.t.TheMechanistAerialArtisan.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Mechanist, Aerial Artisan", 64, Rarity.RARE, mage.cards.t.TheMechanistAerialArtisan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Rise of Sozin", 117, Rarity.MYTHIC, mage.cards.t.TheRiseOfSozin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Rise of Sozin", 356, Rarity.MYTHIC, mage.cards.t.TheRiseOfSozin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Spirit Oasis", 72, Rarity.UNCOMMON, mage.cards.t.TheSpiritOasis.class)); + cards.add(new SetCardInfo("The Unagi of Kyoshi Island", 319, Rarity.RARE, mage.cards.t.TheUnagiOfKyoshiIsland.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Unagi of Kyoshi Island", 77, Rarity.RARE, mage.cards.t.TheUnagiOfKyoshiIsland.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Walls of Ba Sing Se", 261, Rarity.MYTHIC, mage.cards.t.TheWallsOfBaSingSe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Walls of Ba Sing Se", 329, Rarity.MYTHIC, mage.cards.t.TheWallsOfBaSingSe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tiger-Dillo", 155, Rarity.UNCOMMON, mage.cards.t.TigerDillo.class)); + cards.add(new SetCardInfo("Tiger-Seal", 318, Rarity.RARE, mage.cards.t.TigerSeal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tiger-Seal", 75, Rarity.RARE, mage.cards.t.TigerSeal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tolls of War", 245, Rarity.UNCOMMON, mage.cards.t.TollsOfWar.class)); + cards.add(new SetCardInfo("Toph, Hardheaded Teacher", 246, Rarity.RARE, mage.cards.t.TophHardheadedTeacher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toph, Hardheaded Teacher", 384, Rarity.RARE, mage.cards.t.TophHardheadedTeacher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the Blind Bandit", 198, Rarity.UNCOMMON, mage.cards.t.TophTheBlindBandit.class)); cards.add(new SetCardInfo("Toph, the First Metalbender", 247, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the First Metalbender", 353, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Toph, the First Metalbender", 362, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Toph, the First Metalbender", 362, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Treetop Freedom Fighters", 156, Rarity.COMMON, mage.cards.t.TreetopFreedomFighters.class)); + cards.add(new SetCardInfo("True Ancestry", 199, Rarity.UNCOMMON, mage.cards.t.TrueAncestry.class)); + cards.add(new SetCardInfo("Trusty Boomerang", 260, Rarity.UNCOMMON, mage.cards.t.TrustyBoomerang.class)); + cards.add(new SetCardInfo("Tundra Tank", 121, Rarity.UNCOMMON, mage.cards.t.TundraTank.class)); cards.add(new SetCardInfo("Turtle-Duck", 200, Rarity.COMMON, mage.cards.t.TurtleDuck.class)); + cards.add(new SetCardInfo("Twin Blades", 157, Rarity.UNCOMMON, mage.cards.t.TwinBlades.class)); + cards.add(new SetCardInfo("Ty Lee, Artful Acrobat", 158, Rarity.UNCOMMON, mage.cards.t.TyLeeArtfulAcrobat.class)); + cards.add(new SetCardInfo("Ty Lee, Chi Blocker", 371, Rarity.RARE, mage.cards.t.TyLeeChiBlocker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ty Lee, Chi Blocker", 76, Rarity.RARE, mage.cards.t.TyLeeChiBlocker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Uncle Iroh", 248, Rarity.UNCOMMON, mage.cards.u.UncleIroh.class)); + cards.add(new SetCardInfo("United Front", 331, Rarity.MYTHIC, mage.cards.u.UnitedFront.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("United Front", 39, Rarity.MYTHIC, mage.cards.u.UnitedFront.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unlucky Cabbage Merchant", 201, Rarity.UNCOMMON, mage.cards.u.UnluckyCabbageMerchant.class)); + cards.add(new SetCardInfo("Vengeful Villagers", 40, Rarity.UNCOMMON, mage.cards.v.VengefulVillagers.class)); cards.add(new SetCardInfo("Vindictive Warden", 249, Rarity.COMMON, mage.cards.v.VindictiveWarden.class)); + cards.add(new SetCardInfo("Walltop Sentries", 202, Rarity.COMMON, mage.cards.w.WalltopSentries.class)); + cards.add(new SetCardInfo("Wan Shi Tong, Librarian", 320, Rarity.MYTHIC, mage.cards.w.WanShiTongLibrarian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wan Shi Tong, Librarian", 78, Rarity.MYTHIC, mage.cards.w.WanShiTongLibrarian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wandering Musicians", 250, Rarity.COMMON, mage.cards.w.WanderingMusicians.class)); + cards.add(new SetCardInfo("War Balloon", 159, Rarity.UNCOMMON, mage.cards.w.WarBalloon.class)); + cards.add(new SetCardInfo("Wartime Protestors", 160, Rarity.RARE, mage.cards.w.WartimeProtestors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wartime Protestors", 375, Rarity.RARE, mage.cards.w.WartimeProtestors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Water Tribe Captain", 41, Rarity.COMMON, mage.cards.w.WaterTribeCaptain.class)); + cards.add(new SetCardInfo("Water Tribe Rallier", 42, Rarity.UNCOMMON, mage.cards.w.WaterTribeRallier.class)); + cards.add(new SetCardInfo("Waterbender Ascension", 310, Rarity.RARE, mage.cards.w.WaterbenderAscension.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Waterbender Ascension", 79, Rarity.RARE, mage.cards.w.WaterbenderAscension.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Waterbending Lesson", 80, Rarity.COMMON, mage.cards.w.WaterbendingLesson.class)); + cards.add(new SetCardInfo("Waterbending Scroll", 81, Rarity.UNCOMMON, mage.cards.w.WaterbendingScroll.class)); cards.add(new SetCardInfo("Watery Grasp", 82, Rarity.COMMON, mage.cards.w.WateryGrasp.class)); + cards.add(new SetCardInfo("White Lotus Hideout", 281, Rarity.UNCOMMON, mage.cards.w.WhiteLotusHideout.class)); + cards.add(new SetCardInfo("White Lotus Reinforcements", 251, Rarity.UNCOMMON, mage.cards.w.WhiteLotusReinforcements.class)); + cards.add(new SetCardInfo("White Lotus Tile", 262, Rarity.MYTHIC, mage.cards.w.WhiteLotusTile.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("White Lotus Tile", 330, Rarity.MYTHIC, mage.cards.w.WhiteLotusTile.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wolfbat", 122, Rarity.UNCOMMON, mage.cards.w.Wolfbat.class)); + cards.add(new SetCardInfo("Yip Yip!", 43, Rarity.COMMON, mage.cards.y.YipYip.class)); cards.add(new SetCardInfo("Yue, the Moon Spirit", 338, Rarity.RARE, mage.cards.y.YueTheMoonSpirit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Yue, the Moon Spirit", 83, Rarity.RARE, mage.cards.y.YueTheMoonSpirit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Yuyan Archers", 161, Rarity.COMMON, mage.cards.y.YuyanArchers.class)); + cards.add(new SetCardInfo("Zhao, Ruthless Admiral", 252, Rarity.UNCOMMON, mage.cards.z.ZhaoRuthlessAdmiral.class)); + cards.add(new SetCardInfo("Zhao, the Moon Slayer", 162, Rarity.RARE, mage.cards.z.ZhaoTheMoonSlayer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zhao, the Moon Slayer", 376, Rarity.RARE, mage.cards.z.ZhaoTheMoonSlayer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko's Conviction", 123, Rarity.UNCOMMON, mage.cards.z.ZukosConviction.class)); + cards.add(new SetCardInfo("Zuko's Exile", 3, Rarity.COMMON, mage.cards.z.ZukosExile.class)); + cards.add(new SetCardInfo("Zuko, Conflicted", 253, Rarity.RARE, mage.cards.z.ZukoConflicted.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko, Conflicted", 302, Rarity.RARE, mage.cards.z.ZukoConflicted.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko, Exiled Prince", 163, Rarity.UNCOMMON, mage.cards.z.ZukoExiledPrince.class)); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); diff --git a/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java b/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java index a1b357b008b..73a30ae2f1b 100644 --- a/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java +++ b/Mage.Sets/src/mage/sets/AvatarTheLastAirbenderEternal.java @@ -12,7 +12,7 @@ import java.util.List; */ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { - private static final List unfinished = Arrays.asList("Water Whip"); + private static final List unfinished = Arrays.asList("Katara, Seeking Revenge", "Ruthless Waterbender", "Waterbender's Restoration", "Water Whip"); private static final AvatarTheLastAirbenderEternal instance = new AvatarTheLastAirbenderEternal(); @@ -26,56 +26,184 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { this.rotationSet = true; this.hasBasicLands = true; + cards.add(new SetCardInfo("Aang and Katara", 69, Rarity.RARE, mage.cards.a.AangAndKatara.class)); cards.add(new SetCardInfo("Aang's Defense", 211, Rarity.COMMON, mage.cards.a.AangsDefense.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Defense", 266, Rarity.COMMON, mage.cards.a.AangsDefense.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, A Lot to Learn", 146, Rarity.UNCOMMON, mage.cards.a.AangALotToLearn.class)); cards.add(new SetCardInfo("Aang, Air Nomad", 210, Rarity.RARE, mage.cards.a.AangAirNomad.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Air Nomad", 265, Rarity.RARE, mage.cards.a.AangAirNomad.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aang, Airbending Master", 74, Rarity.MYTHIC, mage.cards.a.AangAirbendingMaster.class)); + cards.add(new SetCardInfo("Aang, Airbending Master", 171, Rarity.MYTHIC, mage.cards.a.AangAirbendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aang, Airbending Master", 74, Rarity.MYTHIC, mage.cards.a.AangAirbendingMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aardvark Sloth", 212, Rarity.COMMON, mage.cards.a.AardvarkSloth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aardvark Sloth", 267, Rarity.COMMON, mage.cards.a.AardvarkSloth.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Acrobatic Leap", 151, Rarity.COMMON, mage.cards.a.AcrobaticLeap.class)); + cards.add(new SetCardInfo("Agent of Treachery", 9, Rarity.MYTHIC, mage.cards.a.AgentOfTreachery.class)); + cards.add(new SetCardInfo("Air Nomad Student", 75, Rarity.UNCOMMON, mage.cards.a.AirNomadStudent.class)); cards.add(new SetCardInfo("Allied Teamwork", 213, Rarity.RARE, mage.cards.a.AlliedTeamwork.class)); cards.add(new SetCardInfo("Appa, Aang's Companion", 214, Rarity.UNCOMMON, mage.cards.a.AppaAangsCompanion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Appa, Aang's Companion", 268, Rarity.UNCOMMON, mage.cards.a.AppaAangsCompanion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Appa, the Vigilant", 62, Rarity.RARE, mage.cards.a.AppaTheVigilant.class)); + cards.add(new SetCardInfo("Arcane Signet", 315, Rarity.RARE, mage.cards.a.ArcaneSignet.class)); + cards.add(new SetCardInfo("Azula, Ruthless Firebender", 101, Rarity.MYTHIC, mage.cards.a.AzulaRuthlessFirebender.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azula, Ruthless Firebender", 184, Rarity.MYTHIC, mage.cards.a.AzulaRuthlessFirebender.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Baboon Spirit", 177, Rarity.RARE, mage.cards.b.BaboonSpirit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Baboon Spirit", 89, Rarity.RARE, mage.cards.b.BaboonSpirit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bastion of Remembrance", 160, Rarity.UNCOMMON, mage.cards.b.BastionOfRemembrance.class)); + cards.add(new SetCardInfo("Beastmaster Ascension", 39, Rarity.MYTHIC, mage.cards.b.BeastmasterAscension.class)); + cards.add(new SetCardInfo("Bison Whistle", 131, Rarity.RARE, mage.cards.b.BisonWhistle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bison Whistle", 202, Rarity.RARE, mage.cards.b.BisonWhistle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Black Sun's Zenith", 22, Rarity.MYTHIC, mage.cards.b.BlackSunsZenith.class)); + cards.add(new SetCardInfo("Blasphemous Act", 26, Rarity.MYTHIC, mage.cards.b.BlasphemousAct.class)); + cards.add(new SetCardInfo("Bloodchief Ascension", 23, Rarity.MYTHIC, mage.cards.b.BloodchiefAscension.class)); + cards.add(new SetCardInfo("Bolt Bend", 163, Rarity.UNCOMMON, mage.cards.b.BoltBend.class)); + cards.add(new SetCardInfo("Bosco, Just a Bear", 132, Rarity.UNCOMMON, mage.cards.b.BoscoJustABear.class)); + cards.add(new SetCardInfo("Brainstorm", 155, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Bribery", 10, Rarity.MYTHIC, mage.cards.b.Bribery.class)); + cards.add(new SetCardInfo("Brought Back", 1, Rarity.MYTHIC, mage.cards.b.BroughtBack.class)); + cards.add(new SetCardInfo("Bumi's Feast Lecture", 133, Rarity.UNCOMMON, mage.cards.b.BumisFeastLecture.class)); cards.add(new SetCardInfo("Bumi, Eclectic Earthbender", 248, Rarity.RARE, mage.cards.b.BumiEclecticEarthbender.class)); cards.add(new SetCardInfo("Capital Guard", 234, Rarity.COMMON, mage.cards.c.CapitalGuard.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Capital Guard", 277, Rarity.COMMON, mage.cards.c.CapitalGuard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Captain Sisay", 47, Rarity.MYTHIC, mage.cards.c.CaptainSisay.class)); + cards.add(new SetCardInfo("Cathartic Reunion", 164, Rarity.COMMON, mage.cards.c.CatharticReunion.class)); + cards.add(new SetCardInfo("Chakra Meditation", 179, Rarity.RARE, mage.cards.c.ChakraMeditation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chakra Meditation", 91, Rarity.RARE, mage.cards.c.ChakraMeditation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chong and Lily, Nomads", 113, Rarity.RARE, mage.cards.c.ChongAndLilyNomads.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chong and Lily, Nomads", 192, Rarity.RARE, mage.cards.c.ChongAndLilyNomads.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cityscape Leveler", 53, Rarity.MYTHIC, mage.cards.c.CityscapeLeveler.class)); + cards.add(new SetCardInfo("Clone Legion", 12, Rarity.MYTHIC, mage.cards.c.CloneLegion.class)); + cards.add(new SetCardInfo("Clone", 11, Rarity.MYTHIC, mage.cards.c.Clone.class)); + cards.add(new SetCardInfo("Cloudshift", 152, Rarity.COMMON, mage.cards.c.Cloudshift.class)); + cards.add(new SetCardInfo("Coastal Piracy", 156, Rarity.UNCOMMON, mage.cards.c.CoastalPiracy.class)); + cards.add(new SetCardInfo("Consider", 157, Rarity.COMMON, mage.cards.c.Consider.class)); + cards.add(new SetCardInfo("Cracked Earth Technique", 135, Rarity.UNCOMMON, mage.cards.c.CrackedEarthTechnique.class)); + cards.add(new SetCardInfo("Creeping Crystal Coating", 136, Rarity.UNCOMMON, mage.cards.c.CreepingCrystalCoating.class)); + cards.add(new SetCardInfo("Cruel Tutor", 24, Rarity.MYTHIC, mage.cards.c.CruelTutor.class)); + cards.add(new SetCardInfo("Crystalline Armor", 137, Rarity.RARE, mage.cards.c.CrystallineArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crystalline Armor", 204, Rarity.RARE, mage.cards.c.CrystallineArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dai Li Censor", 102, Rarity.COMMON, mage.cards.d.DaiLiCensor.class)); + cards.add(new SetCardInfo("Dark Deal", 161, Rarity.UNCOMMON, mage.cards.d.DarkDeal.class)); + cards.add(new SetCardInfo("Dark Depths", 56, Rarity.MYTHIC, mage.cards.d.DarkDepths.class)); + cards.add(new SetCardInfo("Deadly Rollick", 309, Rarity.RARE, mage.cards.d.DeadlyRollick.class)); + cards.add(new SetCardInfo("Deer-Dog", 114, Rarity.COMMON, mage.cards.d.DeerDog.class)); + cards.add(new SetCardInfo("Deflecting Swat", 311, Rarity.RARE, mage.cards.d.DeflectingSwat.class)); cards.add(new SetCardInfo("Deny Entry", 222, Rarity.COMMON, mage.cards.d.DenyEntry.class)); + cards.add(new SetCardInfo("Descendants' Path", 167, Rarity.RARE, mage.cards.d.DescendantsPath.class)); + cards.add(new SetCardInfo("Desperate Plea", 103, Rarity.RARE, mage.cards.d.DesperatePlea.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Desperate Plea", 185, Rarity.RARE, mage.cards.d.DesperatePlea.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Diaochan, Artful Beauty", 27, Rarity.MYTHIC, mage.cards.d.DiaochanArtfulBeauty.class)); + cards.add(new SetCardInfo("Diresight", 162, Rarity.COMMON, mage.cards.d.Diresight.class)); + cards.add(new SetCardInfo("Dockside Extortionist", 28, Rarity.MYTHIC, mage.cards.d.DocksideExtortionist.class)); cards.add(new SetCardInfo("Dragon Moose", 235, Rarity.COMMON, mage.cards.d.DragonMoose.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragon Moose", 278, Rarity.COMMON, mage.cards.d.DragonMoose.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dramatic Reversal", 158, Rarity.COMMON, mage.cards.d.DramaticReversal.class)); + cards.add(new SetCardInfo("Drannith Magistrate", 2, Rarity.MYTHIC, mage.cards.d.DrannithMagistrate.class)); + cards.add(new SetCardInfo("Duelist's Heritage", 153, Rarity.RARE, mage.cards.d.DuelistsHeritage.class)); + cards.add(new SetCardInfo("Dutiful Knowledge Seeker", 92, Rarity.UNCOMMON, mage.cards.d.DutifulKnowledgeSeeker.class)); cards.add(new SetCardInfo("Earthbending Student", 249, Rarity.UNCOMMON, mage.cards.e.EarthbendingStudent.class)); + cards.add(new SetCardInfo("Earthshape", 67, Rarity.RARE, mage.cards.e.Earthshape.class)); cards.add(new SetCardInfo("Eel-Hounds", 250, Rarity.UNCOMMON, mage.cards.e.EelHounds.class)); + cards.add(new SetCardInfo("Eladamri's Call", 48, Rarity.MYTHIC, mage.cards.e.EladamrisCall.class)); + cards.add(new SetCardInfo("Elemental Bond", 40, Rarity.MYTHIC, mage.cards.e.ElementalBond.class)); + cards.add(new SetCardInfo("Elephant-Mandrill", 138, Rarity.UNCOMMON, mage.cards.e.ElephantMandrill.class)); cards.add(new SetCardInfo("Elephant-Rat", 228, Rarity.COMMON, mage.cards.e.ElephantRat.class)); + cards.add(new SetCardInfo("Empty City Ruse", 3, Rarity.MYTHIC, mage.cards.e.EmptyCityRuse.class)); + cards.add(new SetCardInfo("Enlightened Tutor", 305, Rarity.RARE, mage.cards.e.EnlightenedTutor.class)); + cards.add(new SetCardInfo("Entomb", 310, Rarity.RARE, mage.cards.e.Entomb.class)); cards.add(new SetCardInfo("Explore", 259, Rarity.COMMON, mage.cards.e.Explore.class)); cards.add(new SetCardInfo("Explosive Shot", 236, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Explosive Shot", 279, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fabled Passage", 57, Rarity.MYTHIC, mage.cards.f.FabledPassage.class)); + cards.add(new SetCardInfo("Fang, Roku's Companion", 115, Rarity.RARE, mage.cards.f.FangRokusCompanion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fang, Roku's Companion", 193, Rarity.RARE, mage.cards.f.FangRokusCompanion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Feed the Swarm", 257, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); + cards.add(new SetCardInfo("Fervor", 29, Rarity.MYTHIC, mage.cards.f.Fervor.class)); + cards.add(new SetCardInfo("Fevered Visions", 49, Rarity.MYTHIC, mage.cards.f.FeveredVisions.class)); + cards.add(new SetCardInfo("Fierce Guardianship", 307, Rarity.RARE, mage.cards.f.FierceGuardianship.class)); + cards.add(new SetCardInfo("Fiery Confluence", 165, Rarity.RARE, mage.cards.f.FieryConfluence.class)); + cards.add(new SetCardInfo("Fire Lord Ozai", 104, Rarity.MYTHIC, mage.cards.f.FireLordOzai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Lord Ozai", 186, Rarity.MYTHIC, mage.cards.f.FireLordOzai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Ambushers", 229, Rarity.COMMON, mage.cards.f.FireNationAmbushers.class)); cards.add(new SetCardInfo("Fire Nation Archers", 237, Rarity.RARE, mage.cards.f.FireNationArchers.class)); + cards.add(new SetCardInfo("Fire Nation Occupation", 105, Rarity.RARE, mage.cards.f.FireNationOccupation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Occupation", 187, Rarity.RARE, mage.cards.f.FireNationOccupation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Salvagers", 106, Rarity.RARE, mage.cards.f.FireNationSalvagers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Salvagers", 188, Rarity.RARE, mage.cards.f.FireNationSalvagers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Sentinels", 230, Rarity.RARE, mage.cards.f.FireNationSentinels.class)); cards.add(new SetCardInfo("Fire Nation Soldier", 238, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation Soldier", 280, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fire Nation Turret", 64, Rarity.RARE, mage.cards.f.FireNationTurret.class)); cards.add(new SetCardInfo("Fire Nation's Conquest", 239, Rarity.UNCOMMON, mage.cards.f.FireNationsConquest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Nation's Conquest", 281, Rarity.UNCOMMON, mage.cards.f.FireNationsConquest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fists of Flame", 166, Rarity.COMMON, mage.cards.f.FistsOfFlame.class)); + cards.add(new SetCardInfo("Flawless Maneuver", 306, Rarity.RARE, mage.cards.f.FlawlessManeuver.class)); cards.add(new SetCardInfo("Flying Dolphin-Fish", 223, Rarity.COMMON, mage.cards.f.FlyingDolphinFish.class)); cards.add(new SetCardInfo("Force of Negation", 13, Rarity.MYTHIC, mage.cards.f.ForceOfNegation.class)); + cards.add(new SetCardInfo("Founding of Omashu", 116, Rarity.UNCOMMON, mage.cards.f.FoundingOfOmashu.class)); + cards.add(new SetCardInfo("Frantic Confrontation", 117, Rarity.UNCOMMON, mage.cards.f.FranticConfrontation.class)); + cards.add(new SetCardInfo("Frantic Search", 159, Rarity.COMMON, mage.cards.f.FranticSearch.class)); + cards.add(new SetCardInfo("Freedom Fighter Recruit", 118, Rarity.COMMON, mage.cards.f.FreedomFighterRecruit.class)); cards.add(new SetCardInfo("Frog-Squirrels", 251, Rarity.COMMON, mage.cards.f.FrogSquirrels.class)); + cards.add(new SetCardInfo("Gamble", 312, Rarity.RARE, mage.cards.g.Gamble.class)); + cards.add(new SetCardInfo("Giant Fly", 107, Rarity.COMMON, mage.cards.g.GiantFly.class)); cards.add(new SetCardInfo("Gilacorn", 231, Rarity.COMMON, mage.cards.g.Gilacorn.class)); + cards.add(new SetCardInfo("Heartbeat of Spring", 42, Rarity.MYTHIC, mage.cards.h.HeartbeatOfSpring.class)); + cards.add(new SetCardInfo("Hei Bai, Forest Guardian", 139, Rarity.MYTHIC, mage.cards.h.HeiBaiForestGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hei Bai, Forest Guardian", 205, Rarity.MYTHIC, mage.cards.h.HeiBaiForestGuardian.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Heroic Intervention", 43, Rarity.MYTHIC, mage.cards.h.HeroicIntervention.class)); cards.add(new SetCardInfo("Hippo-Cows", 252, Rarity.COMMON, mage.cards.h.HippoCows.class)); + cards.add(new SetCardInfo("Hog-Monkey Rampage", 255, Rarity.UNCOMMON, mage.cards.h.HogMonkeyRampage.class)); + cards.add(new SetCardInfo("Hook Swords", 147, Rarity.UNCOMMON, mage.cards.h.HookSwords.class)); + cards.add(new SetCardInfo("Humble Defector", 30, Rarity.MYTHIC, mage.cards.h.HumbleDefector.class)); + cards.add(new SetCardInfo("Imprisoned in the Moon", 14, Rarity.MYTHIC, mage.cards.i.ImprisonedInTheMoon.class)); + cards.add(new SetCardInfo("Inspired Insurgent", 77, Rarity.COMMON, mage.cards.i.InspiredInsurgent.class)); + cards.add(new SetCardInfo("Inspiring Call", 168, Rarity.UNCOMMON, mage.cards.i.InspiringCall.class)); + cards.add(new SetCardInfo("Insurrection", 31, Rarity.MYTHIC, mage.cards.i.Insurrection.class)); + cards.add(new SetCardInfo("Intruder Alarm", 15, Rarity.MYTHIC, mage.cards.i.IntruderAlarm.class)); + cards.add(new SetCardInfo("Iroh, Dragon of the West", 119, Rarity.RARE, mage.cards.i.IrohDragonOfTheWest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iroh, Dragon of the West", 194, Rarity.RARE, mage.cards.i.IrohDragonOfTheWest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Iroh, Firebending Instructor", 240, Rarity.UNCOMMON, mage.cards.i.IrohFirebendingInstructor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Iroh, Firebending Instructor", 282, Rarity.UNCOMMON, mage.cards.i.IrohFirebendingInstructor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jet, Rebel Leader", 172, Rarity.RARE, mage.cards.j.JetRebelLeader.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jet, Rebel Leader", 78, Rarity.RARE, mage.cards.j.JetRebelLeader.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Join the Dance", 50, Rarity.MYTHIC, mage.cards.j.JoinTheDance.class)); + cards.add(new SetCardInfo("Katara's Reversal", 63, Rarity.RARE, mage.cards.k.KatarasReversal.class)); cards.add(new SetCardInfo("Katara, Heroic Healer", 215, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, Heroic Healer", 269, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Katara, Waterbending Master", 93, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class)); + cards.add(new SetCardInfo("Katara, Seeking Revenge", 148, Rarity.UNCOMMON, mage.cards.k.KataraSeekingRevenge.class)); + cards.add(new SetCardInfo("Katara, Waterbending Master", 180, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Katara, Waterbending Master", 93, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kindly Customer", 79, Rarity.COMMON, mage.cards.k.KindlyCustomer.class)); + cards.add(new SetCardInfo("Koala-Sheep", 80, Rarity.COMMON, mage.cards.k.KoalaSheep.class)); + cards.add(new SetCardInfo("Koma, Cosmos Serpent", 51, Rarity.MYTHIC, mage.cards.k.KomaCosmosSerpent.class)); cards.add(new SetCardInfo("Komodo Rhino", 241, Rarity.COMMON, mage.cards.k.KomodoRhino.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Komodo Rhino", 283, Rarity.COMMON, mage.cards.k.KomodoRhino.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kyoshi Warrior Exemplars", 140, Rarity.UNCOMMON, mage.cards.k.KyoshiWarriorExemplars.class)); cards.add(new SetCardInfo("Kyoshi Warrior Guard", 216, Rarity.COMMON, mage.cards.k.KyoshiWarriorGuard.class)); + cards.add(new SetCardInfo("Lightning Bolt", 32, Rarity.MYTHIC, mage.cards.l.LightningBolt.class)); cards.add(new SetCardInfo("Lion Vulture", 232, Rarity.RARE, mage.cards.l.LionVulture.class)); + cards.add(new SetCardInfo("Lita, Mechanical Engineer", 4, Rarity.MYTHIC, mage.cards.l.LitaMechanicalEngineer.class)); + cards.add(new SetCardInfo("Lo and Li, Royal Advisors", 108, Rarity.RARE, mage.cards.l.LoAndLiRoyalAdvisors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lo and Li, Royal Advisors", 189, Rarity.RARE, mage.cards.l.LoAndLiRoyalAdvisors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Longshot, Rebel Bowman", 120, Rarity.UNCOMMON, mage.cards.l.LongshotRebelBowman.class)); + cards.add(new SetCardInfo("Lost in Memories", 121, Rarity.RARE, mage.cards.l.LostInMemories.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lost in Memories", 195, Rarity.RARE, mage.cards.l.LostInMemories.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lost in the Spirit World", 224, Rarity.UNCOMMON, mage.cards.l.LostInTheSpiritWorld.class)); cards.add(new SetCardInfo("Loyal Fire Sage", 242, Rarity.UNCOMMON, mage.cards.l.LoyalFireSage.class)); + cards.add(new SetCardInfo("Mai and Zuko", 68, Rarity.RARE, mage.cards.m.MaiAndZuko.class)); + cards.add(new SetCardInfo("Many Partings", 169, Rarity.COMMON, mage.cards.m.ManyPartings.class)); + cards.add(new SetCardInfo("Master's Guidance", 141, Rarity.RARE, mage.cards.m.MastersGuidance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Master's Guidance", 206, Rarity.RARE, mage.cards.m.MastersGuidance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Match the Odds", 253, Rarity.UNCOMMON, mage.cards.m.MatchTheOdds.class)); cards.add(new SetCardInfo("Mechanical Glider", 256, Rarity.COMMON, mage.cards.m.MechanicalGlider.class)); + cards.add(new SetCardInfo("Meteorite", 54, Rarity.MYTHIC, mage.cards.m.Meteorite.class)); + cards.add(new SetCardInfo("Mirrorwing Dragon", 33, Rarity.MYTHIC, mage.cards.m.MirrorwingDragon.class)); + cards.add(new SetCardInfo("Moku, Meandering Drummer", 122, Rarity.UNCOMMON, mage.cards.m.MokuMeanderingDrummer.class)); + cards.add(new SetCardInfo("Momo's Heist", 72, Rarity.RARE, mage.cards.m.MomosHeist.class)); cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 217, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 270, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Monk Gyatso", 173, Rarity.RARE, mage.cards.m.MonkGyatso.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Monk Gyatso", 81, Rarity.RARE, mage.cards.m.MonkGyatso.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 289, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 291, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -84,7 +212,17 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 294, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 295, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 296, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mystic Remora", 16, Rarity.MYTHIC, mage.cards.m.MysticRemora.class)); + cards.add(new SetCardInfo("Mystical Tutor", 308, Rarity.RARE, mage.cards.m.MysticalTutor.class)); + cards.add(new SetCardInfo("Nightmares and Daydreams", 94, Rarity.RARE, mage.cards.n.NightmaresAndDaydreams.class)); + cards.add(new SetCardInfo("Noxious Gearhulk", 25, Rarity.MYTHIC, mage.cards.n.NoxiousGearhulk.class)); + cards.add(new SetCardInfo("Nyla, Shirshu Sleuth", 109, Rarity.RARE, mage.cards.n.NylaShirshuSleuth.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nyla, Shirshu Sleuth", 190, Rarity.RARE, mage.cards.n.NylaShirshuSleuth.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscuring Haze", 313, Rarity.RARE, mage.cards.o.ObscuringHaze.class)); + cards.add(new SetCardInfo("Overwhelming Victory", 123, Rarity.RARE, mage.cards.o.OverwhelmingVictory.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Overwhelming Victory", 196, Rarity.RARE, mage.cards.o.OverwhelmingVictory.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Path to Redemption", 271, Rarity.COMMON, mage.cards.p.PathToRedemption.class)); + cards.add(new SetCardInfo("Pipsqueak, Rebel Strongarm", 82, Rarity.UNCOMMON, mage.cards.p.PipsqueakRebelStrongarm.class)); cards.add(new SetCardInfo("Plains", 297, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 298, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 299, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -93,38 +231,113 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet { cards.add(new SetCardInfo("Plains", 302, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 303, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 304, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Princess Yue", 95, Rarity.UNCOMMON, mage.cards.p.PrincessYue.class)); + cards.add(new SetCardInfo("Prosperity", 17, Rarity.MYTHIC, mage.cards.p.Prosperity.class)); cards.add(new SetCardInfo("Purple Pentapus", 233, Rarity.COMMON, mage.cards.p.PurplePentapus.class)); cards.add(new SetCardInfo("Razor Rings", 272, Rarity.COMMON, mage.cards.r.RazorRings.class)); + cards.add(new SetCardInfo("Reckless Blaze", 124, Rarity.RARE, mage.cards.r.RecklessBlaze.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckless Blaze", 197, Rarity.RARE, mage.cards.r.RecklessBlaze.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Release to Memory", 5, Rarity.MYTHIC, mage.cards.r.ReleaseToMemory.class)); + cards.add(new SetCardInfo("Rending Volley", 34, Rarity.MYTHIC, mage.cards.r.RendingVolley.class)); + cards.add(new SetCardInfo("Return of the Wildspeaker", 44, Rarity.MYTHIC, mage.cards.r.ReturnOfTheWildspeaker.class)); + cards.add(new SetCardInfo("Rhys the Redeemed", 52, Rarity.MYTHIC, mage.cards.r.RhysTheRedeemed.class)); + cards.add(new SetCardInfo("Rites of Flourishing", 45, Rarity.MYTHIC, mage.cards.r.RitesOfFlourishing.class)); cards.add(new SetCardInfo("Roku's Mastery", 243, Rarity.UNCOMMON, mage.cards.r.RokusMastery.class)); cards.add(new SetCardInfo("Run Amok", 258, Rarity.COMMON, mage.cards.r.RunAmok.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Run Amok", 284, Rarity.COMMON, mage.cards.r.RunAmok.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ruthless Waterbender", 110, Rarity.UNCOMMON, mage.cards.r.RuthlessWaterbender.class)); + cards.add(new SetCardInfo("Sakashima of a Thousand Faces", 18, Rarity.MYTHIC, mage.cards.s.SakashimaOfAThousandFaces.class)); + cards.add(new SetCardInfo("Scarring Memories", 111, Rarity.UNCOMMON, mage.cards.s.ScarringMemories.class)); + cards.add(new SetCardInfo("Scout's Warning", 6, Rarity.MYTHIC, mage.cards.s.ScoutsWarning.class)); + cards.add(new SetCardInfo("Searing Blood", 35, Rarity.MYTHIC, mage.cards.s.SearingBlood.class)); cards.add(new SetCardInfo("Seismic Tutelage", 254, Rarity.RARE, mage.cards.s.SeismicTutelage.class)); + cards.add(new SetCardInfo("Shattering Spree", 36, Rarity.MYTHIC, mage.cards.s.ShatteringSpree.class)); cards.add(new SetCardInfo("Sledding Otter-Penguin", 218, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sledding Otter-Penguin", 273, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Smellerbee, Rebel Fighter", 125, Rarity.RARE, mage.cards.s.SmellerbeeRebelFighter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Smellerbee, Rebel Fighter", 198, Rarity.RARE, mage.cards.s.SmellerbeeRebelFighter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokka and Suki", 71, Rarity.RARE, mage.cards.s.SokkaAndSuki.class)); + cards.add(new SetCardInfo("Sokka's Charge", 66, Rarity.RARE, mage.cards.s.SokkasCharge.class)); + cards.add(new SetCardInfo("Sokka's Sword Training", 84, Rarity.COMMON, mage.cards.s.SokkasSwordTraining.class)); + cards.add(new SetCardInfo("Sokka, Swordmaster", 174, Rarity.MYTHIC, mage.cards.s.SokkaSwordmaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokka, Swordmaster", 83, Rarity.MYTHIC, mage.cards.s.SokkaSwordmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 219, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 274, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Cabbage Merchant", 134, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class)); + cards.add(new SetCardInfo("Sol Ring", 316, Rarity.RARE, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Solid Ground", 142, Rarity.UNCOMMON, mage.cards.s.SolidGround.class)); + cards.add(new SetCardInfo("Stand United", 149, Rarity.COMMON, mage.cards.s.StandUnited.class)); + cards.add(new SetCardInfo("Standstill", 19, Rarity.MYTHIC, mage.cards.s.Standstill.class)); + cards.add(new SetCardInfo("Storm of Memories", 126, Rarity.RARE, mage.cards.s.StormOfMemories.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm of Memories", 199, Rarity.RARE, mage.cards.s.StormOfMemories.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suki, Kyoshi Captain", 175, Rarity.RARE, mage.cards.s.SukiKyoshiCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suki, Kyoshi Captain", 85, Rarity.RARE, mage.cards.s.SukiKyoshiCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sunbaked Canyon", 58, Rarity.MYTHIC, mage.cards.s.SunbakedCanyon.class)); + cards.add(new SetCardInfo("Sundial of the Infinite", 55, Rarity.MYTHIC, mage.cards.s.SundialOfTheInfinite.class)); + cards.add(new SetCardInfo("Suspicious Bookcase", 170, Rarity.UNCOMMON, mage.cards.s.SuspiciousBookcase.class)); + cards.add(new SetCardInfo("Swampbenders", 65, Rarity.RARE, mage.cards.s.Swampbenders.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 317, Rarity.RARE, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Tale of Katara and Toph", 143, Rarity.RARE, mage.cards.t.TaleOfKataraAndToph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Katara and Toph", 207, Rarity.RARE, mage.cards.t.TaleOfKataraAndToph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Momo", 176, Rarity.RARE, mage.cards.t.TaleOfMomo.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tale of Momo", 86, Rarity.RARE, mage.cards.t.TaleOfMomo.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tarnished Citadel", 59, Rarity.MYTHIC, mage.cards.t.TarnishedCitadel.class)); + cards.add(new SetCardInfo("Taunting Challenge", 46, Rarity.MYTHIC, mage.cards.t.TauntingChallenge.class)); + cards.add(new SetCardInfo("Tectonic Split", 144, Rarity.RARE, mage.cards.t.TectonicSplit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tectonic Split", 208, Rarity.RARE, mage.cards.t.TectonicSplit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teferi's Protection", 7, Rarity.MYTHIC, mage.cards.t.TeferisProtection.class)); + cards.add(new SetCardInfo("That's Rough Buddy", 87, Rarity.UNCOMMON, mage.cards.t.ThatsRoughBuddy.class)); + cards.add(new SetCardInfo("The Art of Tea", 129, Rarity.COMMON, mage.cards.t.TheArtOfTea.class)); + cards.add(new SetCardInfo("The Blue Spirit", 178, Rarity.RARE, mage.cards.t.TheBlueSpirit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Blue Spirit", 90, Rarity.RARE, mage.cards.t.TheBlueSpirit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Cabbage Merchant", 134, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Cabbage Merchant", 203, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Duke, Rebel Sentry", 76, Rarity.UNCOMMON, mage.cards.t.TheDukeRebelSentry.class)); cards.add(new SetCardInfo("The Great Henge", 41, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class)); cards.add(new SetCardInfo("The Terror of Serpent's Pass", 225, Rarity.RARE, mage.cards.t.TheTerrorOfSerpentsPass.class)); + cards.add(new SetCardInfo("Three Dreams", 8, Rarity.MYTHIC, mage.cards.t.ThreeDreams.class)); cards.add(new SetCardInfo("Thriving Bluff", 260, Rarity.COMMON, mage.cards.t.ThrivingBluff.class)); cards.add(new SetCardInfo("Thriving Grove", 261, Rarity.COMMON, mage.cards.t.ThrivingGrove.class)); cards.add(new SetCardInfo("Thriving Heath", 262, Rarity.COMMON, mage.cards.t.ThrivingHeath.class)); cards.add(new SetCardInfo("Thriving Isle", 263, Rarity.COMMON, mage.cards.t.ThrivingIsle.class)); cards.add(new SetCardInfo("Thriving Moor", 264, Rarity.COMMON, mage.cards.t.ThrivingMoor.class)); + cards.add(new SetCardInfo("Toph, Earthbending Master", 145, Rarity.MYTHIC, mage.cards.t.TophEarthbendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toph, Earthbending Master", 209, Rarity.MYTHIC, mage.cards.t.TophEarthbendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toph, Greatest Earthbender", 70, Rarity.RARE, mage.cards.t.TophGreatestEarthbender.class)); + cards.add(new SetCardInfo("Toucan-Puffin", 88, Rarity.COMMON, mage.cards.t.ToucanPuffin.class)); + cards.add(new SetCardInfo("Training Grounds", 20, Rarity.MYTHIC, mage.cards.t.TrainingGrounds.class)); + cards.add(new SetCardInfo("Treetop Village", 60, Rarity.MYTHIC, mage.cards.t.TreetopVillage.class)); + cards.add(new SetCardInfo("Tui and La, Moon and Ocean", 181, Rarity.RARE, mage.cards.t.TuiAndLaMoonAndOcean.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tui and La, Moon and Ocean", 96, Rarity.RARE, mage.cards.t.TuiAndLaMoonAndOcean.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tundra Wall", 220, Rarity.COMMON, mage.cards.t.TundraWall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tundra Wall", 275, Rarity.COMMON, mage.cards.t.TundraWall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Turtle-Seals", 226, Rarity.COMMON, mage.cards.t.TurtleSeals.class)); + cards.add(new SetCardInfo("Unagi's Spray", 97, Rarity.COMMON, mage.cards.u.UnagisSpray.class)); + cards.add(new SetCardInfo("Uncle's Musings", 73, Rarity.RARE, mage.cards.u.UnclesMusings.class)); + cards.add(new SetCardInfo("Valakut, the Molten Pinnacle", 61, Rarity.MYTHIC, mage.cards.v.ValakutTheMoltenPinnacle.class)); + cards.add(new SetCardInfo("Valorous Stance", 154, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class)); + cards.add(new SetCardInfo("Visions of Beyond", 21, Rarity.MYTHIC, mage.cards.v.VisionsOfBeyond.class)); + cards.add(new SetCardInfo("Volcanic Torrent", 37, Rarity.MYTHIC, mage.cards.v.VolcanicTorrent.class)); + cards.add(new SetCardInfo("Wan Shi Tong, All-Knowing", 182, Rarity.MYTHIC, mage.cards.w.WanShiTongAllKnowing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wan Shi Tong, All-Knowing", 98, Rarity.MYTHIC, mage.cards.w.WanShiTongAllKnowing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warship Scout", 244, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warship Scout", 285, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Warstorm Surge", 38, Rarity.MYTHIC, mage.cards.w.WarstormSurge.class)); cards.add(new SetCardInfo("Water Whip", 227, Rarity.RARE, mage.cards.w.WaterWhip.class)); + cards.add(new SetCardInfo("Waterbender's Restoration", 183, Rarity.RARE, mage.cards.w.WaterbendersRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Waterbender's Restoration", 99, Rarity.RARE, mage.cards.w.WaterbendersRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Whirlwind Technique", 100, Rarity.UNCOMMON, mage.cards.w.WhirlwindTechnique.class)); cards.add(new SetCardInfo("Wolf Cove Villager", 221, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wolf Cove Villager", 276, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Worldly Tutor", 314, Rarity.RARE, mage.cards.w.WorldlyTutor.class)); cards.add(new SetCardInfo("Zhao, the Seething Flame", 245, Rarity.UNCOMMON, mage.cards.z.ZhaoTheSeethingFlame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zhao, the Seething Flame", 286, Rarity.UNCOMMON, mage.cards.z.ZhaoTheSeethingFlame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko's Offense", 247, Rarity.COMMON, mage.cards.z.ZukosOffense.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko's Offense", 288, Rarity.COMMON, mage.cards.z.ZukosOffense.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko, Avatar Hunter", 246, Rarity.RARE, mage.cards.z.ZukoAvatarHunter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zuko, Avatar Hunter", 287, Rarity.RARE, mage.cards.z.ZukoAvatarHunter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko, Firebending Master", 127, Rarity.MYTHIC, mage.cards.z.ZukoFirebendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko, Firebending Master", 200, Rarity.MYTHIC, mage.cards.z.ZukoFirebendingMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zuko, Seeking Honor", 150, Rarity.UNCOMMON, mage.cards.z.ZukoSeekingHonor.class)); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } diff --git a/Mage.Sets/src/mage/sets/CommanderCollectionBlack.java b/Mage.Sets/src/mage/sets/CommanderCollectionBlack.java index f54c7d6122e..9162e1962f1 100644 --- a/Mage.Sets/src/mage/sets/CommanderCollectionBlack.java +++ b/Mage.Sets/src/mage/sets/CommanderCollectionBlack.java @@ -22,7 +22,6 @@ public final class CommanderCollectionBlack extends ExpansionSet { cards.add(new SetCardInfo("Command Tower", 8, Rarity.RARE, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Ghoulcaller Gisa", 2, Rarity.MYTHIC, mage.cards.g.GhoulcallerGisa.class)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", 1, Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", 1, Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); cards.add(new SetCardInfo("Ophiomancer", 3, Rarity.RARE, mage.cards.o.Ophiomancer.class)); cards.add(new SetCardInfo("Phyrexian Arena", 4, Rarity.RARE, mage.cards.p.PhyrexianArena.class)); diff --git a/Mage.Sets/src/mage/sets/CoreSet2019.java b/Mage.Sets/src/mage/sets/CoreSet2019.java index 09d37b5b5f0..5a814ec341e 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2019.java +++ b/Mage.Sets/src/mage/sets/CoreSet2019.java @@ -220,7 +220,6 @@ public final class CoreSet2019 extends ExpansionSet { cards.add(new SetCardInfo("Mystic Archaeologist", 63, Rarity.RARE, mage.cards.m.MysticArchaeologist.class)); cards.add(new SetCardInfo("Naturalize", 190, Rarity.COMMON, mage.cards.n.Naturalize.class)); cards.add(new SetCardInfo("Nexus of Fate", 306, Rarity.MYTHIC, mage.cards.n.NexusOfFate.class)); - cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 218, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 218, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class)); cards.add(new SetCardInfo("Nightmare's Thirst", 111, Rarity.UNCOMMON, mage.cards.n.NightmaresThirst.class)); cards.add(new SetCardInfo("Novice Knight", 30, Rarity.UNCOMMON, mage.cards.n.NoviceKnight.class)); diff --git a/Mage.Sets/src/mage/sets/CoreSet2019Promos.java b/Mage.Sets/src/mage/sets/CoreSet2019Promos.java index 9ebf7e2f241..490e6681905 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2019Promos.java +++ b/Mage.Sets/src/mage/sets/CoreSet2019Promos.java @@ -77,7 +77,6 @@ public class CoreSet2019Promos extends ExpansionSet { cards.add(new SetCardInfo("Mistcaller", "62s", Rarity.RARE, mage.cards.m.Mistcaller.class)); cards.add(new SetCardInfo("Murder", 110, Rarity.UNCOMMON, mage.cards.m.Murder.class)); cards.add(new SetCardInfo("Mystic Archaeologist", "63s", Rarity.RARE, mage.cards.m.MysticArchaeologist.class)); - cards.add(new SetCardInfo("Nicol Bolas, the Arisen", "218s", Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", "218s", Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class)); cards.add(new SetCardInfo("Omniscience", "65s", Rarity.MYTHIC, mage.cards.o.Omniscience.class)); cards.add(new SetCardInfo("One with the Machine", "66s", Rarity.RARE, mage.cards.o.OneWithTheMachine.class)); diff --git a/Mage.Sets/src/mage/sets/DarkAscension.java b/Mage.Sets/src/mage/sets/DarkAscension.java index 8abef1f136e..9273ed0220e 100644 --- a/Mage.Sets/src/mage/sets/DarkAscension.java +++ b/Mage.Sets/src/mage/sets/DarkAscension.java @@ -1,10 +1,8 @@ - package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; @@ -44,7 +42,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Alpha Brawl", 82, Rarity.RARE, mage.cards.a.AlphaBrawl.class)); cards.add(new SetCardInfo("Altar of the Lost", 144, Rarity.UNCOMMON, mage.cards.a.AltarOfTheLost.class)); cards.add(new SetCardInfo("Archangel's Light", 1, Rarity.MYTHIC, mage.cards.a.ArchangelsLight.class)); - cards.add(new SetCardInfo("Archdemon of Greed", 71, Rarity.RARE, mage.cards.a.ArchdemonOfGreed.class)); cards.add(new SetCardInfo("Artful Dodge", 27, Rarity.COMMON, mage.cards.a.ArtfulDodge.class)); cards.add(new SetCardInfo("Avacyn's Collar", 145, Rarity.UNCOMMON, mage.cards.a.AvacynsCollar.class)); cards.add(new SetCardInfo("Bar the Door", 2, Rarity.COMMON, mage.cards.b.BarTheDoor.class)); @@ -57,7 +54,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Burden of Guilt", 4, Rarity.COMMON, mage.cards.b.BurdenOfGuilt.class)); cards.add(new SetCardInfo("Burning Oil", 84, Rarity.UNCOMMON, mage.cards.b.BurningOil.class)); cards.add(new SetCardInfo("Call to the Kindred", 30, Rarity.RARE, mage.cards.c.CallToTheKindred.class)); - cards.add(new SetCardInfo("Chalice of Death", 146, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class)); cards.add(new SetCardInfo("Chalice of Life", 146, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class)); cards.add(new SetCardInfo("Chant of the Skifsang", 31, Rarity.COMMON, mage.cards.c.ChantOfTheSkifsang.class)); cards.add(new SetCardInfo("Chill of Foreboding", 32, Rarity.UNCOMMON, mage.cards.c.ChillOfForeboding.class)); @@ -100,7 +96,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Gavony Ironwright", 9, Rarity.UNCOMMON, mage.cards.g.GavonyIronwright.class)); cards.add(new SetCardInfo("Geralf's Messenger", 63, Rarity.RARE, mage.cards.g.GeralfsMessenger.class)); cards.add(new SetCardInfo("Geralf's Mindcrusher", 37, Rarity.RARE, mage.cards.g.GeralfsMindcrusher.class)); - cards.add(new SetCardInfo("Ghastly Haunting", 50, Rarity.UNCOMMON, mage.cards.g.GhastlyHaunting.class)); cards.add(new SetCardInfo("Ghoultree", 115, Rarity.RARE, mage.cards.g.Ghoultree.class)); cards.add(new SetCardInfo("Grafdigger's Cage", 149, Rarity.RARE, mage.cards.g.GrafdiggersCage.class)); cards.add(new SetCardInfo("Gravecrawler", 64, Rarity.RARE, mage.cards.g.Gravecrawler.class)); @@ -121,7 +116,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Helvault", 151, Rarity.MYTHIC, mage.cards.h.Helvault.class)); cards.add(new SetCardInfo("Highborn Ghoul", 68, Rarity.COMMON, mage.cards.h.HighbornGhoul.class)); cards.add(new SetCardInfo("Hinterland Hermit", 94, Rarity.COMMON, mage.cards.h.HinterlandHermit.class)); - cards.add(new SetCardInfo("Hinterland Scourge", 94, Rarity.COMMON, mage.cards.h.HinterlandScourge.class)); cards.add(new SetCardInfo("Hollowhenge Beast", 118, Rarity.COMMON, mage.cards.h.HollowhengeBeast.class)); cards.add(new SetCardInfo("Hollowhenge Spirit", 10, Rarity.UNCOMMON, mage.cards.h.HollowhengeSpirit.class)); cards.add(new SetCardInfo("Hunger of the Howlpack", 119, Rarity.COMMON, mage.cards.h.HungerOfTheHowlpack.class)); @@ -134,18 +128,15 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Increasing Vengeance", 95, Rarity.RARE, mage.cards.i.IncreasingVengeance.class)); cards.add(new SetCardInfo("Jar of Eyeballs", 152, Rarity.RARE, mage.cards.j.JarOfEyeballs.class)); cards.add(new SetCardInfo("Kessig Recluse", 121, Rarity.COMMON, mage.cards.k.KessigRecluse.class)); - cards.add(new SetCardInfo("Krallenhorde Killer", 133, Rarity.RARE, mage.cards.k.KrallenhordeKiller.class)); cards.add(new SetCardInfo("Lambholt Elder", 122, Rarity.UNCOMMON, mage.cards.l.LambholtElder.class)); cards.add(new SetCardInfo("Lingering Souls", 12, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); cards.add(new SetCardInfo("Lost in the Woods", 123, Rarity.RARE, mage.cards.l.LostInTheWoods.class)); cards.add(new SetCardInfo("Loyal Cathar", 13, Rarity.COMMON, mage.cards.l.LoyalCathar.class)); cards.add(new SetCardInfo("Markov Blademaster", 96, Rarity.RARE, mage.cards.m.MarkovBlademaster.class)); - cards.add(new SetCardInfo("Markov's Servant", 55, Rarity.COMMON, mage.cards.m.MarkovsServant.class)); cards.add(new SetCardInfo("Markov Warlord", 97, Rarity.UNCOMMON, mage.cards.m.MarkovWarlord.class)); cards.add(new SetCardInfo("Midnight Guard", 14, Rarity.COMMON, mage.cards.m.MidnightGuard.class)); cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 70, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class)); cards.add(new SetCardInfo("Mondronen Shaman", 98, Rarity.RARE, mage.cards.m.MondronenShaman.class)); - cards.add(new SetCardInfo("Moonscarred Werewolf", 125, Rarity.COMMON, mage.cards.m.MoonscarredWerewolf.class)); cards.add(new SetCardInfo("Moonveil Dragon", 99, Rarity.MYTHIC, mage.cards.m.MoonveilDragon.class)); cards.add(new SetCardInfo("Mystic Retrieval", 42, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class)); cards.add(new SetCardInfo("Nearheath Stalker", 100, Rarity.COMMON, mage.cards.n.NearheathStalker.class)); @@ -155,7 +146,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Niblis of the Urn", 16, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class)); cards.add(new SetCardInfo("Predator Ooze", 124, Rarity.RARE, mage.cards.p.PredatorOoze.class)); cards.add(new SetCardInfo("Pyreheart Wolf", 101, Rarity.UNCOMMON, mage.cards.p.PyreheartWolf.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 140, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Ravenous Demon", 71, Rarity.RARE, mage.cards.r.RavenousDemon.class)); cards.add(new SetCardInfo("Ray of Revelation", 17, Rarity.COMMON, mage.cards.r.RayOfRevelation.class)); cards.add(new SetCardInfo("Reap the Seagraf", 72, Rarity.COMMON, mage.cards.r.ReapTheSeagraf.class)); @@ -173,7 +163,6 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Shriekgeist", 49, Rarity.COMMON, mage.cards.s.Shriekgeist.class)); cards.add(new SetCardInfo("Sightless Ghoul", 73, Rarity.COMMON, mage.cards.s.SightlessGhoul.class)); cards.add(new SetCardInfo("Silverclaw Griffin", 21, Rarity.COMMON, mage.cards.s.SilverclawGriffin.class)); - cards.add(new SetCardInfo("Silverpelt Werewolf", 122, Rarity.UNCOMMON, mage.cards.s.SilverpeltWerewolf.class)); cards.add(new SetCardInfo("Skillful Lunge", 22, Rarity.COMMON, mage.cards.s.SkillfulLunge.class)); cards.add(new SetCardInfo("Skirsdag Flayer", 74, Rarity.UNCOMMON, mage.cards.s.SkirsdagFlayer.class)); cards.add(new SetCardInfo("Somberwald Dryad", 126, Rarity.COMMON, mage.cards.s.SomberwaldDryad.class)); @@ -190,22 +179,18 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Thraben Doomsayer", 25, Rarity.RARE, mage.cards.t.ThrabenDoomsayer.class)); cards.add(new SetCardInfo("Thraben Heretic", 26, Rarity.UNCOMMON, mage.cards.t.ThrabenHeretic.class)); cards.add(new SetCardInfo("Torch Fiend", 106, Rarity.COMMON, mage.cards.t.TorchFiend.class)); - cards.add(new SetCardInfo("Tovolar's Magehunter", 98, Rarity.RARE, mage.cards.t.TovolarsMagehunter.class)); cards.add(new SetCardInfo("Tower Geist", 53, Rarity.UNCOMMON, mage.cards.t.TowerGeist.class)); cards.add(new SetCardInfo("Tracker's Instincts", 128, Rarity.UNCOMMON, mage.cards.t.TrackersInstincts.class)); cards.add(new SetCardInfo("Tragic Slip", 76, Rarity.COMMON, mage.cards.t.TragicSlip.class)); cards.add(new SetCardInfo("Ulvenwald Bear", 129, Rarity.COMMON, mage.cards.u.UlvenwaldBear.class)); cards.add(new SetCardInfo("Undying Evil", 77, Rarity.COMMON, mage.cards.u.UndyingEvil.class)); - cards.add(new SetCardInfo("Unhallowed Cathar", 13, Rarity.COMMON, mage.cards.u.UnhallowedCathar.class)); cards.add(new SetCardInfo("Vault of the Archangel", 158, Rarity.RARE, mage.cards.v.VaultOfTheArchangel.class)); cards.add(new SetCardInfo("Vengeful Vampire", 78, Rarity.UNCOMMON, mage.cards.v.VengefulVampire.class)); cards.add(new SetCardInfo("Village Survivors", 130, Rarity.UNCOMMON, mage.cards.v.VillageSurvivors.class)); cards.add(new SetCardInfo("Vorapede", 131, Rarity.MYTHIC, mage.cards.v.Vorapede.class)); cards.add(new SetCardInfo("Wakedancer", 79, Rarity.UNCOMMON, mage.cards.w.Wakedancer.class)); cards.add(new SetCardInfo("Warden of the Wall", 153, Rarity.UNCOMMON, mage.cards.w.WardenOfTheWall.class)); - cards.add(new SetCardInfo("Werewolf Ransacker", 81, Rarity.UNCOMMON, mage.cards.w.WerewolfRansacker.class)); cards.add(new SetCardInfo("Wild Hunger", 132, Rarity.COMMON, mage.cards.w.WildHunger.class)); - cards.add(new SetCardInfo("Withengar Unbound", 147, Rarity.MYTHIC, mage.cards.w.WithengarUnbound.class)); cards.add(new SetCardInfo("Wolfbitten Captive", 133, Rarity.RARE, mage.cards.w.WolfbittenCaptive.class)); cards.add(new SetCardInfo("Wolfhunter's Quiver", 154, Rarity.UNCOMMON, mage.cards.w.WolfhuntersQuiver.class)); cards.add(new SetCardInfo("Wrack with Madness", 107, Rarity.COMMON, mage.cards.w.WrackWithMadness.class)); @@ -251,8 +236,8 @@ class DarkAscensionCollator implements BoosterCollator { private final CardRun land = new CardRun(false, "ISD_250", "ISD_251", "ISD_252", "ISD_253", "ISD_254", "ISD_255", "ISD_256", "ISD_257", "ISD_258", "ISD_259", "ISD_260", "ISD_261", "ISD_262", "ISD_263", "ISD_264"); private final BoosterStructure AAAAABBBB = new BoosterStructure( - commonA, commonA, commonA, commonA, commonA, - commonB, commonB, commonB, commonB + 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); diff --git a/Mage.Sets/src/mage/sets/DarkAscensionPromos.java b/Mage.Sets/src/mage/sets/DarkAscensionPromos.java index 4de0aa57778..9901edd99bd 100644 --- a/Mage.Sets/src/mage/sets/DarkAscensionPromos.java +++ b/Mage.Sets/src/mage/sets/DarkAscensionPromos.java @@ -20,12 +20,10 @@ public class DarkAscensionPromos extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Archdemon of Greed", "71*", Rarity.RARE, mage.cards.a.ArchdemonOfGreed.class)); cards.add(new SetCardInfo("Gravecrawler", "64*", Rarity.RARE, mage.cards.g.Gravecrawler.class)); cards.add(new SetCardInfo("Mondronen Shaman", "98*", Rarity.RARE, mage.cards.m.MondronenShaman.class)); cards.add(new SetCardInfo("Ravenous Demon", "71*", Rarity.RARE, mage.cards.r.RavenousDemon.class)); cards.add(new SetCardInfo("Strangleroot Geist", 127, Rarity.UNCOMMON, mage.cards.s.StranglerootGeist.class)); - cards.add(new SetCardInfo("Tovolar's Magehunter", "98*", Rarity.RARE, mage.cards.t.TovolarsMagehunter.class)); cards.add(new SetCardInfo("Zombie Apocalypse", 80, Rarity.RARE, mage.cards.z.ZombieApocalypse.class)); } } diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java index 476e986740b..dd4e6aa7428 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java @@ -43,6 +43,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Blazemire Verge", 329, Rarity.RARE, mage.cards.b.BlazemireVerge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bleeding Woods", 257, Rarity.COMMON, mage.cards.b.BleedingWoods.class)); cards.add(new SetCardInfo("Boilerbilges Ripper", 127, Rarity.COMMON, mage.cards.b.BoilerbilgesRipper.class)); + cards.add(new SetCardInfo("Bottomless Pool // Locker Room", 43, Rarity.UNCOMMON, mage.cards.b.BottomlessPoolLockerRoom.class)); cards.add(new SetCardInfo("Break Down the Door", 170, Rarity.UNCOMMON, mage.cards.b.BreakDownTheDoor.class)); cards.add(new SetCardInfo("Broodspinner", 211, Rarity.UNCOMMON, mage.cards.b.Broodspinner.class)); cards.add(new SetCardInfo("Cackling Slasher", 85, Rarity.COMMON, mage.cards.c.CacklingSlasher.class)); @@ -69,13 +70,19 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Cynical Loner", 89, Rarity.UNCOMMON, mage.cards.c.CynicalLoner.class)); cards.add(new SetCardInfo("Daggermaw Megalodon", 48, Rarity.COMMON, mage.cards.d.DaggermawMegalodon.class)); cards.add(new SetCardInfo("Dashing Bloodsucker", 90, Rarity.UNCOMMON, mage.cards.d.DashingBloodsucker.class)); + cards.add(new SetCardInfo("Dazzling Theater // Prop Room", 3, Rarity.RARE, mage.cards.d.DazzlingTheaterPropRoom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dazzling Theater // Prop Room", 334, Rarity.RARE, mage.cards.d.DazzlingTheaterPropRoom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Defiant Survivor", 175, Rarity.UNCOMMON, mage.cards.d.DefiantSurvivor.class)); + cards.add(new SetCardInfo("Defiled Crypt // Cadaver Lab", 91, Rarity.UNCOMMON, mage.cards.d.DefiledCryptCadaverLab.class)); cards.add(new SetCardInfo("Demonic Counsel", 310, Rarity.RARE, mage.cards.d.DemonicCounsel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Counsel", 92, Rarity.RARE, mage.cards.d.DemonicCounsel.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Derelict Attic // Widow's Walk", 93, Rarity.COMMON, mage.cards.d.DerelictAtticWidowsWalk.class)); cards.add(new SetCardInfo("Dissection Tools", 245, Rarity.RARE, mage.cards.d.DissectionTools.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dissection Tools", 385, Rarity.RARE, mage.cards.d.DissectionTools.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Disturbing Mirth", 212, Rarity.UNCOMMON, mage.cards.d.DisturbingMirth.class)); cards.add(new SetCardInfo("Diversion Specialist", 132, Rarity.UNCOMMON, mage.cards.d.DiversionSpecialist.class)); + cards.add(new SetCardInfo("Dollmaker's Shop // Porcelain Gallery", 335, Rarity.MYTHIC, mage.cards.d.DollmakersShopPorcelainGallery.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dollmaker's Shop // Porcelain Gallery", 4, Rarity.MYTHIC, mage.cards.d.DollmakersShopPorcelainGallery.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Don't Make a Sound", 49, Rarity.COMMON, mage.cards.d.DontMakeASound.class)); cards.add(new SetCardInfo("Doomsday Excruciator", 346, Rarity.RARE, mage.cards.d.DoomsdayExcruciator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doomsday Excruciator", 94, Rarity.RARE, mage.cards.d.DoomsdayExcruciator.class, NON_FULL_USE_VARIOUS)); @@ -139,19 +146,26 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Frantic Strength", 179, Rarity.COMMON, mage.cards.f.FranticStrength.class)); cards.add(new SetCardInfo("Friendly Ghost", 12, Rarity.COMMON, mage.cards.f.FriendlyGhost.class)); cards.add(new SetCardInfo("Friendly Teddy", 247, Rarity.COMMON, mage.cards.f.FriendlyTeddy.class)); + cards.add(new SetCardInfo("Funeral Room // Awakening Hall", 100, Rarity.MYTHIC, mage.cards.f.FuneralRoomAwakeningHall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Funeral Room // Awakening Hall", 338, Rarity.MYTHIC, mage.cards.f.FuneralRoomAwakeningHall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Get Out", 60, Rarity.UNCOMMON, mage.cards.g.GetOut.class)); cards.add(new SetCardInfo("Ghost Vacuum", 248, Rarity.RARE, mage.cards.g.GhostVacuum.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghost Vacuum", 326, Rarity.RARE, mage.cards.g.GhostVacuum.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghostly Dancers", 13, Rarity.RARE, mage.cards.g.GhostlyDancers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghostly Dancers", 302, Rarity.RARE, mage.cards.g.GhostlyDancers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghostly Keybearer", 61, Rarity.UNCOMMON, mage.cards.g.GhostlyKeybearer.class)); cards.add(new SetCardInfo("Give In to Violence", 101, Rarity.COMMON, mage.cards.g.GiveInToViolence.class)); + cards.add(new SetCardInfo("Glassworks // Shattered Yard", 137, Rarity.COMMON, mage.cards.g.GlassworksShatteredYard.class)); cards.add(new SetCardInfo("Glimmer Seeker", 14, Rarity.UNCOMMON, mage.cards.g.GlimmerSeeker.class)); cards.add(new SetCardInfo("Glimmerburst", 62, Rarity.COMMON, mage.cards.g.Glimmerburst.class)); cards.add(new SetCardInfo("Glimmerlight", 249, Rarity.COMMON, mage.cards.g.Glimmerlight.class)); cards.add(new SetCardInfo("Gloomlake Verge", 260, Rarity.RARE, mage.cards.g.GloomlakeVerge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gloomlake Verge", 331, Rarity.RARE, mage.cards.g.GloomlakeVerge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grab the Prize", 138, Rarity.COMMON, mage.cards.g.GrabThePrize.class)); + cards.add(new SetCardInfo("Grand Entryway // Elegant Rotunda", 15, Rarity.COMMON, mage.cards.g.GrandEntrywayElegantRotunda.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Grand Entryway // Elegant Rotunda", 287, Rarity.COMMON, mage.cards.g.GrandEntrywayElegantRotunda.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grasping Longneck", 180, Rarity.COMMON, mage.cards.g.GraspingLongneck.class)); + cards.add(new SetCardInfo("Greenhouse // Rickety Gazebo", 181, Rarity.UNCOMMON, mage.cards.g.GreenhouseRicketyGazebo.class)); cards.add(new SetCardInfo("Gremlin Tamer", 215, Rarity.UNCOMMON, mage.cards.g.GremlinTamer.class)); cards.add(new SetCardInfo("Grievous Wound", 102, Rarity.RARE, mage.cards.g.GrievousWound.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grievous Wound", 375, Rarity.RARE, mage.cards.g.GrievousWound.class, NON_FULL_USE_VARIOUS)); @@ -211,11 +225,15 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Marina Vendrell's Grimoire", 64, Rarity.RARE, mage.cards.m.MarinaVendrellsGrimoire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Marvin, Murderous Mimic", 253, Rarity.RARE, mage.cards.m.MarvinMurderousMimic.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Marvin, Murderous Mimic", 367, Rarity.RARE, mage.cards.m.MarvinMurderousMimic.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Meat Locker // Drowned Diner", 65, Rarity.COMMON, mage.cards.m.MeatLockerDrownedDiner.class)); cards.add(new SetCardInfo("Meathook Massacre II", 108, Rarity.MYTHIC, mage.cards.m.MeathookMassacreII.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Meathook Massacre II", 293, Rarity.MYTHIC, mage.cards.m.MeathookMassacreII.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Meathook Massacre II", 311, Rarity.MYTHIC, mage.cards.m.MeathookMassacreII.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Miasma Demon", 109, Rarity.UNCOMMON, mage.cards.m.MiasmaDemon.class)); cards.add(new SetCardInfo("Midnight Mayhem", 222, Rarity.UNCOMMON, mage.cards.m.MidnightMayhem.class)); + cards.add(new SetCardInfo("Mirror Room // Fractured Realm", 67, Rarity.MYTHIC, mage.cards.m.MirrorRoomFracturedRealm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirror Room // Fractured Realm", 337, Rarity.MYTHIC, mage.cards.m.MirrorRoomFracturedRealm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Moldering Gym // Weight Room", 190, Rarity.COMMON, mage.cards.m.MolderingGymWeightRoom.class)); cards.add(new SetCardInfo("Monstrous Emergence", 191, Rarity.COMMON, mage.cards.m.MonstrousEmergence.class)); cards.add(new SetCardInfo("Most Valuable Slayer", 144, Rarity.COMMON, mage.cards.m.MostValuableSlayer.class)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); @@ -260,6 +278,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Overlord of the Mistmoors", 370, Rarity.MYTHIC, mage.cards.o.OverlordOfTheMistmoors.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overlord of the Mistmoors", 387, Rarity.MYTHIC, mage.cards.o.OverlordOfTheMistmoors.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overlord of the Mistmoors", 397, Rarity.MYTHIC, mage.cards.o.OverlordOfTheMistmoors.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Painter's Studio // Defaced Gallery", 147, Rarity.UNCOMMON, mage.cards.p.PaintersStudioDefacedGallery.class)); cards.add(new SetCardInfo("Paranormal Analyst", 69, Rarity.UNCOMMON, mage.cards.p.ParanormalAnalyst.class)); cards.add(new SetCardInfo("Patched Plaything", 24, Rarity.UNCOMMON, mage.cards.p.PatchedPlaything.class)); cards.add(new SetCardInfo("Patchwork Beastie", 195, Rarity.UNCOMMON, mage.cards.p.PatchworkBeastie.class)); @@ -276,6 +295,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Pyroclasm", 149, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pyroclasm", 413, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ragged Playmate", 150, Rarity.COMMON, mage.cards.r.RaggedPlaymate.class)); + cards.add(new SetCardInfo("Rampaging Soulrager", 151, Rarity.COMMON, mage.cards.r.RampagingSoulrager.class)); cards.add(new SetCardInfo("Raucous Carnival", 266, Rarity.COMMON, mage.cards.r.RaucousCarnival.class)); cards.add(new SetCardInfo("Razorkin Hordecaller", 152, Rarity.UNCOMMON, mage.cards.r.RazorkinHordecaller.class)); cards.add(new SetCardInfo("Razorkin Needlehead", 153, Rarity.RARE, mage.cards.r.RazorkinNeedlehead.class, NON_FULL_USE_VARIOUS)); @@ -284,11 +304,15 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Reluctant Role Model", 26, Rarity.RARE, mage.cards.r.ReluctantRoleModel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reluctant Role Model", 289, Rarity.RARE, mage.cards.r.ReluctantRoleModel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reluctant Role Model", 303, Rarity.RARE, mage.cards.r.ReluctantRoleModel.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Restricted Office // Lecture Hall", 342, Rarity.RARE, mage.cards.r.RestrictedOfficeLectureHall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Restricted Office // Lecture Hall", 227, Rarity.RARE, mage.cards.r.RestrictedOfficeLectureHall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Resurrected Cultist", 115, Rarity.COMMON, mage.cards.r.ResurrectedCultist.class)); cards.add(new SetCardInfo("Rip, Spawn Hunter", 228, Rarity.RARE, mage.cards.r.RipSpawnHunter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rip, Spawn Hunter", 362, Rarity.RARE, mage.cards.r.RipSpawnHunter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ripchain Razorkin", 154, Rarity.COMMON, mage.cards.r.RipchainRazorkin.class)); cards.add(new SetCardInfo("Rite of the Moth", 229, Rarity.UNCOMMON, mage.cards.r.RiteOfTheMoth.class)); + cards.add(new SetCardInfo("Roaring Furnace // Steaming Sauna", 343, Rarity.RARE, mage.cards.r.RoaringFurnaceSteamingSauna.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Roaring Furnace // Steaming Sauna", 230, Rarity.RARE, mage.cards.r.RoaringFurnaceSteamingSauna.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rootwise Survivor", 196, Rarity.UNCOMMON, mage.cards.r.RootwiseSurvivor.class)); cards.add(new SetCardInfo("Savior of the Small", 27, Rarity.UNCOMMON, mage.cards.s.SaviorOfTheSmall.class)); cards.add(new SetCardInfo("Saw", 254, Rarity.UNCOMMON, mage.cards.s.Saw.class)); @@ -318,6 +342,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Stay Hidden, Stay Silent", 291, Rarity.UNCOMMON, mage.cards.s.StayHiddenStaySilent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stay Hidden, Stay Silent", 74, Rarity.UNCOMMON, mage.cards.s.StayHiddenStaySilent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Strangled Cemetery", 268, Rarity.COMMON, mage.cards.s.StrangledCemetery.class)); + cards.add(new SetCardInfo("Surgical Suite // Hospital Room", 34, Rarity.UNCOMMON, mage.cards.s.SurgicalSuiteHospitalRoom.class)); cards.add(new SetCardInfo("Swamp", 274, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", 281, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 282, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); @@ -339,6 +364,7 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Thornspire Verge", 270, Rarity.RARE, mage.cards.t.ThornspireVerge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thornspire Verge", 333, Rarity.RARE, mage.cards.t.ThornspireVerge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Threats Around Every Corner", 200, Rarity.UNCOMMON, mage.cards.t.ThreatsAroundEveryCorner.class)); + cards.add(new SetCardInfo("Ticket Booth // Tunnel of Hate", 158, Rarity.COMMON, mage.cards.t.TicketBoothTunnelOfHate.class)); cards.add(new SetCardInfo("Toby, Beastie Befriender", 35, Rarity.RARE, mage.cards.t.TobyBeastieBefriender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toby, Beastie Befriender", 356, Rarity.RARE, mage.cards.t.TobyBeastieBefriender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Trapped in the Screen", 36, Rarity.COMMON, mage.cards.t.TrappedInTheScreen.class)); @@ -357,6 +383,9 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Undead Sprinter", 350, Rarity.RARE, mage.cards.u.UndeadSprinter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Under the Skin", 203, Rarity.UNCOMMON, mage.cards.u.UnderTheSkin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Under the Skin", 323, Rarity.UNCOMMON, mage.cards.u.UnderTheSkin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Underwater Tunnel // Slimy Aquarium", 79, Rarity.COMMON, mage.cards.u.UnderwaterTunnelSlimyAquarium.class)); + cards.add(new SetCardInfo("Unholy Annex // Ritual Chamber", 118, Rarity.RARE, mage.cards.u.UnholyAnnexRitualChamber.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unholy Annex // Ritual Chamber", 339, Rarity.RARE, mage.cards.u.UnholyAnnexRitualChamber.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Unidentified Hovership", 305, Rarity.RARE, mage.cards.u.UnidentifiedHovership.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Unidentified Hovership", 37, Rarity.RARE, mage.cards.u.UnidentifiedHovership.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Unnerving Grasp", 80, Rarity.UNCOMMON, mage.cards.u.UnnervingGrasp.class)); @@ -385,6 +414,8 @@ public final class DuskmournHouseOfHorror extends ExpansionSet { cards.add(new SetCardInfo("Victor, Valgavoth's Seneschal", 364, Rarity.RARE, mage.cards.v.VictorValgavothsSeneschal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vile Mutilator", 122, Rarity.UNCOMMON, mage.cards.v.VileMutilator.class)); cards.add(new SetCardInfo("Violent Urge", 164, Rarity.UNCOMMON, mage.cards.v.ViolentUrge.class)); + cards.add(new SetCardInfo("Walk-In Closet // Forgotten Cellar", 205, Rarity.MYTHIC, mage.cards.w.WalkInClosetForgottenCellar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Walk-In Closet // Forgotten Cellar", 341, Rarity.MYTHIC, mage.cards.w.WalkInClosetForgottenCellar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Waltz of Rage", 165, Rarity.RARE, mage.cards.w.WaltzOfRage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Waltz of Rage", 318, Rarity.RARE, mage.cards.w.WaltzOfRage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wary Watchdog", 206, Rarity.COMMON, mage.cards.w.WaryWatchdog.class)); diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java index 353c7fc6d8a..691e9746422 100644 --- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java +++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorrorCommander.java @@ -23,13 +23,14 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Aesi, Tyrant of Gyre Strait", 210, Rarity.MYTHIC, mage.cards.a.AesiTyrantOfGyreStrait.class)); cards.add(new SetCardInfo("Aether Gale", 109, Rarity.RARE, mage.cards.a.AetherGale.class)); cards.add(new SetCardInfo("Aminatou's Augury", 71, Rarity.RARE, mage.cards.a.AminatousAugury.class)); - cards.add(new SetCardInfo("Ancient Cellarspawn", 16, Rarity.RARE, mage.cards.a.AncientCellarspawn.class)); + cards.add(new SetCardInfo("Ancient Cellarspawn", 16, Rarity.RARE, mage.cards.a.AncientCellarspawn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ancient Cellarspawn", 47, Rarity.RARE, mage.cards.a.AncientCellarspawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arachnogenesis", 169, Rarity.RARE, mage.cards.a.Arachnogenesis.class)); cards.add(new SetCardInfo("Arcane Denial", 110, Rarity.COMMON, mage.cards.a.ArcaneDenial.class)); cards.add(new SetCardInfo("Arcane Sanctum", 259, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); cards.add(new SetCardInfo("Arcane Signet", 92, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Archetype of Imagination", 111, Rarity.UNCOMMON, mage.cards.a.ArchetypeOfImagination.class)); - cards.add(new SetCardInfo("Archon of Cruelty", 371, Rarity.MYTHIC, mage.cards.a.ArchonOfCruelty.class, FULL_ART)); + cards.add(new SetCardInfo("Archon of Cruelty", 371, Rarity.MYTHIC, mage.cards.a.ArchonOfCruelty.class)); cards.add(new SetCardInfo("Arixmethes, Slumbering Isle", 211, Rarity.RARE, mage.cards.a.ArixmethesSlumberingIsle.class)); cards.add(new SetCardInfo("Arvinox, the Mind Flail", 130, Rarity.MYTHIC, mage.cards.a.ArvinoxTheMindFlail.class)); cards.add(new SetCardInfo("Ash Barrens", 260, Rarity.COMMON, mage.cards.a.AshBarrens.class)); @@ -39,7 +40,8 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Auramancer", 97, Rarity.COMMON, mage.cards.a.Auramancer.class)); cards.add(new SetCardInfo("Azorius Chancery", 261, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); cards.add(new SetCardInfo("Azorius Signet", 240, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); - cards.add(new SetCardInfo("Barbflare Gremlin", 26, Rarity.RARE, mage.cards.b.BarbflareGremlin.class)); + cards.add(new SetCardInfo("Barbflare Gremlin", 26, Rarity.RARE, mage.cards.b.BarbflareGremlin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Barbflare Gremlin", 55, Rarity.RARE, mage.cards.b.BarbflareGremlin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Barren Moor", 262, Rarity.UNCOMMON, mage.cards.b.BarrenMoor.class)); cards.add(new SetCardInfo("Basilisk Collar", 241, Rarity.RARE, mage.cards.b.BasiliskCollar.class)); cards.add(new SetCardInfo("Bastion of Remembrance", 131, Rarity.UNCOMMON, mage.cards.b.BastionOfRemembrance.class)); @@ -73,13 +75,15 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Combustible Gearhulk", 163, Rarity.MYTHIC, mage.cards.c.CombustibleGearhulk.class)); cards.add(new SetCardInfo("Command Tower", 96, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Commander's Sphere", 244, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); - cards.add(new SetCardInfo("Convert to Slime", 37, Rarity.RARE, mage.cards.c.ConvertToSlime.class)); + cards.add(new SetCardInfo("Convert to Slime", 37, Rarity.RARE, mage.cards.c.ConvertToSlime.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Convert to Slime", 64, Rarity.RARE, mage.cards.c.ConvertToSlime.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Counterspell", 114, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); cards.add(new SetCardInfo("Crawling Sensation", 173, Rarity.UNCOMMON, mage.cards.c.CrawlingSensation.class)); cards.add(new SetCardInfo("Crypt Ghast", 368, Rarity.MYTHIC, mage.cards.c.CryptGhast.class)); cards.add(new SetCardInfo("Culling Ritual", 85, Rarity.RARE, mage.cards.c.CullingRitual.class)); cards.add(new SetCardInfo("Cultivate", 174, Rarity.COMMON, mage.cards.c.Cultivate.class)); - cards.add(new SetCardInfo("Curator Beastie", 30, Rarity.RARE, mage.cards.c.CuratorBeastie.class)); + cards.add(new SetCardInfo("Curator Beastie", 30, Rarity.RARE, mage.cards.c.CuratorBeastie.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Curator Beastie", 58, Rarity.RARE, mage.cards.c.CuratorBeastie.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Damn", 369, Rarity.MYTHIC, mage.cards.d.Damn.class)); cards.add(new SetCardInfo("Darkmoss Bridge", 269, Rarity.COMMON, mage.cards.d.DarkmossBridge.class)); cards.add(new SetCardInfo("Deadbridge Chant", 215, Rarity.MYTHIC, mage.cards.d.DeadbridgeChant.class)); @@ -87,14 +91,18 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Deathmist Raptor", 176, Rarity.MYTHIC, mage.cards.d.DeathmistRaptor.class)); cards.add(new SetCardInfo("Deathreap Ritual", 86, Rarity.UNCOMMON, mage.cards.d.DeathreapRitual.class)); cards.add(new SetCardInfo("Decree of Pain", 136, Rarity.RARE, mage.cards.d.DecreeOfPain.class)); - cards.add(new SetCardInfo("Deluge of Doom", 18, Rarity.RARE, mage.cards.d.DelugeOfDoom.class)); - cards.add(new SetCardInfo("Demolisher Spawn", 31, Rarity.RARE, mage.cards.d.DemolisherSpawn.class)); + cards.add(new SetCardInfo("Deluge of Doom", 18, Rarity.RARE, mage.cards.d.DelugeOfDoom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Deluge of Doom", 48, Rarity.RARE, mage.cards.d.DelugeOfDoom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Demolisher Spawn", 31, Rarity.RARE, mage.cards.d.DemolisherSpawn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Demolisher Spawn", 59, Rarity.RARE, mage.cards.d.DemolisherSpawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demon of Fate's Design", 137, Rarity.RARE, mage.cards.d.DemonOfFatesDesign.class)); - cards.add(new SetCardInfo("Demonic Covenant", 19, Rarity.RARE, mage.cards.d.DemonicCovenant.class)); + cards.add(new SetCardInfo("Demonic Covenant", 19, Rarity.RARE, mage.cards.d.DemonicCovenant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Demonic Covenant", 49, Rarity.RARE, mage.cards.d.DemonicCovenant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diabolic Vision", 87, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); cards.add(new SetCardInfo("Dig Through Time", 115, Rarity.RARE, mage.cards.d.DigThroughTime.class)); cards.add(new SetCardInfo("Dimir Aqueduct", 270, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); - cards.add(new SetCardInfo("Disorienting Choice", 32, Rarity.RARE, mage.cards.d.DisorientingChoice.class)); + cards.add(new SetCardInfo("Disorienting Choice", 32, Rarity.RARE, mage.cards.d.DisorientingChoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Disorienting Choice", 60, Rarity.RARE, mage.cards.d.DisorientingChoice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doomwake Giant", 138, Rarity.RARE, mage.cards.d.DoomwakeGiant.class)); cards.add(new SetCardInfo("Dragonskull Summit", 271, Rarity.RARE, mage.cards.d.DragonskullSummit.class)); cards.add(new SetCardInfo("Dream Eater", 116, Rarity.MYTHIC, mage.cards.d.DreamEater.class)); @@ -106,27 +114,33 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Evolving Wilds", 274, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Exhume", 370, Rarity.MYTHIC, mage.cards.e.Exhume.class)); cards.add(new SetCardInfo("Exotic Orchard", 275, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); + cards.add(new SetCardInfo("Experimental Lab // Staff Room", 33, Rarity.RARE, mage.cards.e.ExperimentalLabStaffRoom.class)); cards.add(new SetCardInfo("Explosive Vegetation", 177, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Extravagant Replication", 117, Rarity.RARE, mage.cards.e.ExtravagantReplication.class)); cards.add(new SetCardInfo("Ezuri's Predation", 178, Rarity.RARE, mage.cards.e.EzurisPredation.class)); cards.add(new SetCardInfo("Falkenrath Noble", 140, Rarity.COMMON, mage.cards.f.FalkenrathNoble.class)); cards.add(new SetCardInfo("Fate Unraveler", 141, Rarity.RARE, mage.cards.f.FateUnraveler.class)); - cards.add(new SetCardInfo("Fear of Sleep Paralysis", 12, Rarity.RARE, mage.cards.f.FearOfSleepParalysis.class)); + cards.add(new SetCardInfo("Fear of Sleep Paralysis", 12, Rarity.RARE, mage.cards.f.FearOfSleepParalysis.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fear of Sleep Paralysis", 43, Rarity.RARE, mage.cards.f.FearOfSleepParalysis.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Feed the Swarm", 78, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); cards.add(new SetCardInfo("Fellwar Stone", 245, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); cards.add(new SetCardInfo("Flooded Grove", 276, Rarity.RARE, mage.cards.f.FloodedGrove.class)); cards.add(new SetCardInfo("Florian, Voldaren Scion", 217, Rarity.RARE, mage.cards.f.FlorianVoldarenScion.class)); cards.add(new SetCardInfo("Foreboding Ruins", 277, Rarity.RARE, mage.cards.f.ForebodingRuins.class)); - cards.add(new SetCardInfo("Formless Genesis", 34, Rarity.RARE, mage.cards.f.FormlessGenesis.class)); + cards.add(new SetCardInfo("Formless Genesis", 34, Rarity.RARE, mage.cards.f.FormlessGenesis.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Formless Genesis", 61, Rarity.RARE, mage.cards.f.FormlessGenesis.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geothermal Bog", 278, Rarity.COMMON, mage.cards.g.GeothermalBog.class)); cards.add(new SetCardInfo("Giant Adephage", 179, Rarity.MYTHIC, mage.cards.g.GiantAdephage.class)); - cards.add(new SetCardInfo("Giggling Skitterspike", 39, Rarity.RARE, mage.cards.g.GigglingSkitterspike.class)); - cards.add(new SetCardInfo("Gleeful Arsonist", 27, Rarity.RARE, mage.cards.g.GleefulArsonist.class)); - cards.add(new SetCardInfo("Glitch Interpreter", 13, Rarity.RARE, mage.cards.g.GlitchInterpreter.class)); + cards.add(new SetCardInfo("Giggling Skitterspike", 39, Rarity.RARE, mage.cards.g.GigglingSkitterspike.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Giggling Skitterspike", 66, Rarity.RARE, mage.cards.g.GigglingSkitterspike.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gleeful Arsonist", 27, Rarity.RARE, mage.cards.g.GleefulArsonist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gleeful Arsonist", 56, Rarity.RARE, mage.cards.g.GleefulArsonist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glitch Interpreter", 13, Rarity.RARE, mage.cards.g.GlitchInterpreter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glitch Interpreter", 44, Rarity.RARE, mage.cards.g.GlitchInterpreter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gnarlwood Dryad", 180, Rarity.UNCOMMON, mage.cards.g.GnarlwoodDryad.class)); cards.add(new SetCardInfo("Golgari Rot Farm", 279, Rarity.UNCOMMON, mage.cards.g.GolgariRotFarm.class)); cards.add(new SetCardInfo("Golgari Signet", 246, Rarity.UNCOMMON, mage.cards.g.GolgariSignet.class)); - cards.add(new SetCardInfo("Goryo's Vengeance", 372, Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class, FULL_ART)); + cards.add(new SetCardInfo("Goryo's Vengeance", 372, Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class)); cards.add(new SetCardInfo("Grapple with the Past", 82, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class)); cards.add(new SetCardInfo("Graven Cairns", 280, Rarity.RARE, mage.cards.g.GravenCairns.class)); cards.add(new SetCardInfo("Gray Merchant of Asphodel", 142, Rarity.UNCOMMON, mage.cards.g.GrayMerchantOfAsphodel.class)); @@ -148,7 +162,8 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Infernal Grasp", 143, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class)); cards.add(new SetCardInfo("Inkshield", 221, Rarity.RARE, mage.cards.i.Inkshield.class)); cards.add(new SetCardInfo("Inscription of Abundance", 186, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class)); - cards.add(new SetCardInfo("Into the Pit", 20, Rarity.RARE, mage.cards.i.IntoThePit.class)); + cards.add(new SetCardInfo("Into the Pit", 20, Rarity.RARE, mage.cards.i.IntoThePit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Into the Pit", 50, Rarity.RARE, mage.cards.i.IntoThePit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ishkanah, Grafwidow", 187, Rarity.MYTHIC, mage.cards.i.IshkanahGrafwidow.class)); cards.add(new SetCardInfo("Jungle Hollow", 285, Rarity.COMMON, mage.cards.j.JungleHollow.class)); cards.add(new SetCardInfo("Kaervek the Merciless", 222, Rarity.RARE, mage.cards.k.KaervekTheMerciless.class)); @@ -161,14 +176,15 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Life Insurance", 224, Rarity.RARE, mage.cards.l.LifeInsurance.class)); cards.add(new SetCardInfo("Light Up the Stage", 166, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); cards.add(new SetCardInfo("Lightning Greaves", 93, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class)); - cards.add(new SetCardInfo("Living Death", 373, Rarity.MYTHIC, mage.cards.l.LivingDeath.class, FULL_ART)); + cards.add(new SetCardInfo("Living Death", 373, Rarity.MYTHIC, mage.cards.l.LivingDeath.class)); cards.add(new SetCardInfo("Llanowar Wastes", 287, Rarity.RARE, mage.cards.l.LlanowarWastes.class)); cards.add(new SetCardInfo("Mask of Griselbrand", 145, Rarity.RARE, mage.cards.m.MaskOfGriselbrand.class)); cards.add(new SetCardInfo("Massacre Girl", 146, Rarity.RARE, mage.cards.m.MassacreGirl.class)); cards.add(new SetCardInfo("Massacre Wurm", 147, Rarity.MYTHIC, mage.cards.m.MassacreWurm.class)); cards.add(new SetCardInfo("Mayhem Devil", 225, Rarity.UNCOMMON, mage.cards.m.MayhemDevil.class)); cards.add(new SetCardInfo("Mesa Enchantress", 68, Rarity.RARE, mage.cards.m.MesaEnchantress.class)); - cards.add(new SetCardInfo("Metamorphosis Fanatic", 21, Rarity.RARE, mage.cards.m.MetamorphosisFanatic.class)); + cards.add(new SetCardInfo("Metamorphosis Fanatic", 21, Rarity.RARE, mage.cards.m.MetamorphosisFanatic.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Metamorphosis Fanatic", 51, Rarity.RARE, mage.cards.m.MetamorphosisFanatic.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mind Stone", 248, Rarity.UNCOMMON, mage.cards.m.MindStone.class)); cards.add(new SetCardInfo("Mirrormade", 120, Rarity.RARE, mage.cards.m.Mirrormade.class)); cards.add(new SetCardInfo("Mogis, God of Slaughter", 89, Rarity.MYTHIC, mage.cards.m.MogisGodOfSlaughter.class)); @@ -199,8 +215,10 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Overflowing Basin", 293, Rarity.RARE, mage.cards.o.OverflowingBasin.class)); cards.add(new SetCardInfo("Oversimplify", 228, Rarity.RARE, mage.cards.o.Oversimplify.class)); cards.add(new SetCardInfo("Overwhelming Stampede", 192, Rarity.RARE, mage.cards.o.OverwhelmingStampede.class)); - cards.add(new SetCardInfo("Persistent Constrictor", 22, Rarity.RARE, mage.cards.p.PersistentConstrictor.class)); - cards.add(new SetCardInfo("Phenomenon Investigators", 38, Rarity.RARE, mage.cards.p.PhenomenonInvestigators.class)); + cards.add(new SetCardInfo("Persistent Constrictor", 22, Rarity.RARE, mage.cards.p.PersistentConstrictor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Persistent Constrictor", 52, Rarity.RARE, mage.cards.p.PersistentConstrictor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phenomenon Investigators", 38, Rarity.RARE, mage.cards.p.PhenomenonInvestigators.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phenomenon Investigators", 65, Rarity.RARE, mage.cards.p.PhenomenonInvestigators.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ponder", 73, Rarity.COMMON, mage.cards.p.Ponder.class)); cards.add(new SetCardInfo("Portent", 74, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Primordial Mist", 123, Rarity.RARE, mage.cards.p.PrimordialMist.class)); @@ -217,23 +235,27 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Read the Bones", 154, Rarity.COMMON, mage.cards.r.ReadTheBones.class)); cards.add(new SetCardInfo("Reality Shift", 125, Rarity.UNCOMMON, mage.cards.r.RealityShift.class)); cards.add(new SetCardInfo("Reanimate", 155, Rarity.RARE, mage.cards.r.Reanimate.class)); - cards.add(new SetCardInfo("Redress Fate", 9, Rarity.RARE, mage.cards.r.RedressFate.class)); + cards.add(new SetCardInfo("Redress Fate", 41, Rarity.RARE, mage.cards.r.RedressFate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Redress Fate", 9, Rarity.RARE, mage.cards.r.RedressFate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reliquary Tower", 295, Rarity.UNCOMMON, mage.cards.r.ReliquaryTower.class)); cards.add(new SetCardInfo("Rendmaw, Creaking Nest", 5, Rarity.MYTHIC, mage.cards.r.RendmawCreakingNest.class)); cards.add(new SetCardInfo("Retreat to Coralhelm", 126, Rarity.UNCOMMON, mage.cards.r.RetreatToCoralhelm.class)); cards.add(new SetCardInfo("Return to Dust", 102, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class)); - cards.add(new SetCardInfo("Sadistic Shell Game", 24, Rarity.RARE, mage.cards.s.SadisticShellGame.class)); + cards.add(new SetCardInfo("Sadistic Shell Game", 24, Rarity.RARE, mage.cards.s.SadisticShellGame.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sadistic Shell Game", 53, Rarity.RARE, mage.cards.s.SadisticShellGame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sakura-Tribe Elder", 194, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class)); cards.add(new SetCardInfo("Sandwurm Convergence", 195, Rarity.RARE, mage.cards.s.SandwurmConvergence.class)); cards.add(new SetCardInfo("Scavenging Ooze", 196, Rarity.RARE, mage.cards.s.ScavengingOoze.class)); cards.add(new SetCardInfo("Scroll of Fate", 251, Rarity.RARE, mage.cards.s.ScrollOfFate.class)); cards.add(new SetCardInfo("Scute Swarm", 197, Rarity.RARE, mage.cards.s.ScuteSwarm.class)); - cards.add(new SetCardInfo("Seance Board", 40, Rarity.RARE, mage.cards.s.SeanceBoard.class)); + cards.add(new SetCardInfo("Seance Board", 40, Rarity.RARE, mage.cards.s.SeanceBoard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Seance Board", 67, Rarity.RARE, mage.cards.s.SeanceBoard.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Shadowblood Ridge", 296, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class)); cards.add(new SetCardInfo("Shark Typhoon", 127, Rarity.RARE, mage.cards.s.SharkTyphoon.class)); cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 198, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class)); cards.add(new SetCardInfo("Shivan Gorge", 297, Rarity.RARE, mage.cards.s.ShivanGorge.class)); - cards.add(new SetCardInfo("Shriekwood Devourer", 35, Rarity.RARE, mage.cards.s.ShriekwoodDevourer.class)); + cards.add(new SetCardInfo("Shriekwood Devourer", 35, Rarity.RARE, mage.cards.s.ShriekwoodDevourer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shriekwood Devourer", 62, Rarity.RARE, mage.cards.s.ShriekwoodDevourer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 103, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); cards.add(new SetCardInfo("Sign in Blood", 156, Rarity.COMMON, mage.cards.s.SignInBlood.class)); cards.add(new SetCardInfo("Simic Growth Chamber", 298, Rarity.UNCOMMON, mage.cards.s.SimicGrowthChamber.class)); @@ -241,19 +263,23 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("Skaab Ruinator", 128, Rarity.MYTHIC, mage.cards.s.SkaabRuinator.class)); cards.add(new SetCardInfo("Skola Grovedancer", 199, Rarity.COMMON, mage.cards.s.SkolaGrovedancer.class)); cards.add(new SetCardInfo("Smoldering Marsh", 299, Rarity.RARE, mage.cards.s.SmolderingMarsh.class)); - cards.add(new SetCardInfo("Soaring Lightbringer", 11, Rarity.RARE, mage.cards.s.SoaringLightbringer.class)); + cards.add(new SetCardInfo("Soaring Lightbringer", 11, Rarity.RARE, mage.cards.s.SoaringLightbringer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soaring Lightbringer", 42, Rarity.RARE, mage.cards.s.SoaringLightbringer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sol Ring", 94, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Solemn Simulacrum", 253, Rarity.RARE, mage.cards.s.SolemnSimulacrum.class)); cards.add(new SetCardInfo("Sphere of Safety", 104, Rarity.UNCOMMON, mage.cards.s.SphereOfSafety.class)); + cards.add(new SetCardInfo("Spiked Corridor // Torture Pit", 28, Rarity.RARE, mage.cards.s.SpikedCorridorTorturePit.class)); cards.add(new SetCardInfo("Spinerock Knoll", 300, Rarity.RARE, mage.cards.s.SpinerockKnoll.class)); cards.add(new SetCardInfo("Spirit-Sister's Call", 232, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class)); cards.add(new SetCardInfo("Spiteful Visions", 233, Rarity.RARE, mage.cards.s.SpitefulVisions.class)); - cards.add(new SetCardInfo("Star Athlete", 29, Rarity.RARE, mage.cards.s.StarAthlete.class)); + cards.add(new SetCardInfo("Star Athlete", 29, Rarity.RARE, mage.cards.s.StarAthlete.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Star Athlete", 57, Rarity.RARE, mage.cards.s.StarAthlete.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Starfield Mystic", 105, Rarity.RARE, mage.cards.s.StarfieldMystic.class)); cards.add(new SetCardInfo("Stitcher's Supplier", 157, Rarity.UNCOMMON, mage.cards.s.StitchersSupplier.class)); cards.add(new SetCardInfo("Stormfist Crusader", 234, Rarity.RARE, mage.cards.s.StormfistCrusader.class)); cards.add(new SetCardInfo("Sulfurous Springs", 301, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); - cards.add(new SetCardInfo("Suspended Sentence", 25, Rarity.RARE, mage.cards.s.SuspendedSentence.class)); + cards.add(new SetCardInfo("Suspended Sentence", 25, Rarity.RARE, mage.cards.s.SuspendedSentence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suspended Sentence", 54, Rarity.RARE, mage.cards.s.SuspendedSentence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Suspicious Bookcase", 95, Rarity.UNCOMMON, mage.cards.s.SuspiciousBookcase.class)); cards.add(new SetCardInfo("Swords to Plowshares", 106, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); cards.add(new SetCardInfo("Syr Konrad, the Grim", 158, Rarity.UNCOMMON, mage.cards.s.SyrKonradTheGrim.class)); @@ -280,7 +306,8 @@ public final class DuskmournHouseOfHorrorCommander extends ExpansionSet { cards.add(new SetCardInfo("The Lord of Pain", 3, Rarity.MYTHIC, mage.cards.t.TheLordOfPain.class)); cards.add(new SetCardInfo("The Master of Keys", 4, Rarity.MYTHIC, mage.cards.t.TheMasterOfKeys.class)); cards.add(new SetCardInfo("Theater of Horrors", 236, Rarity.RARE, mage.cards.t.TheaterOfHorrors.class)); - cards.add(new SetCardInfo("They Came from the Pipes", 14, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class)); + cards.add(new SetCardInfo("They Came from the Pipes", 14, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("They Came from the Pipes", 45, Rarity.RARE, mage.cards.t.TheyCameFromThePipes.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thirst for Meaning", 129, Rarity.COMMON, mage.cards.t.ThirstForMeaning.class)); cards.add(new SetCardInfo("Thornwood Falls", 314, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Thought Vessel", 256, Rarity.COMMON, mage.cards.t.ThoughtVessel.class)); diff --git a/Mage.Sets/src/mage/sets/EldritchMoon.java b/Mage.Sets/src/mage/sets/EldritchMoon.java index 5b9e2d9967f..76aa983a42f 100644 --- a/Mage.Sets/src/mage/sets/EldritchMoon.java +++ b/Mage.Sets/src/mage/sets/EldritchMoon.java @@ -42,12 +42,10 @@ public final class EldritchMoon extends ExpansionSet { this.numBoosterDoubleFaced = 1; cards.add(new SetCardInfo("Abandon Reason", 115, Rarity.UNCOMMON, mage.cards.a.AbandonReason.class)); - cards.add(new SetCardInfo("Abolisher of Bloodlines", 111, Rarity.RARE, mage.cards.a.AbolisherOfBloodlines.class)); cards.add(new SetCardInfo("Abundant Maw", 1, Rarity.UNCOMMON, mage.cards.a.AbundantMaw.class)); cards.add(new SetCardInfo("Advanced Stitchwing", 49, Rarity.UNCOMMON, mage.cards.a.AdvancedStitchwing.class)); cards.add(new SetCardInfo("Alchemist's Greeting", 116, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class)); cards.add(new SetCardInfo("Assembled Alphas", 117, Rarity.RARE, mage.cards.a.AssembledAlphas.class)); - cards.add(new SetCardInfo("Aurora of Emrakul", 193, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class)); cards.add(new SetCardInfo("Backwoods Survivalists", 150, Rarity.COMMON, mage.cards.b.BackwoodsSurvivalists.class)); cards.add(new SetCardInfo("Bedlam Reveler", 118, Rarity.RARE, mage.cards.b.BedlamReveler.class)); cards.add(new SetCardInfo("Blessed Alliance", 13, Rarity.UNCOMMON, mage.cards.b.BlessedAlliance.class)); @@ -74,7 +72,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Collective Brutality", 85, Rarity.RARE, mage.cards.c.CollectiveBrutality.class)); cards.add(new SetCardInfo("Collective Defiance", 123, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Collective Effort", 17, Rarity.RARE, mage.cards.c.CollectiveEffort.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 124, Rarity.UNCOMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 124, Rarity.UNCOMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Contingency Plan", 52, Rarity.COMMON, mage.cards.c.ContingencyPlan.class)); cards.add(new SetCardInfo("Convolute", 53, Rarity.COMMON, mage.cards.c.Convolute.class)); @@ -97,7 +94,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Docent of Perfection", 56, Rarity.RARE, mage.cards.d.DocentOfPerfection.class)); cards.add(new SetCardInfo("Drag Under", 57, Rarity.COMMON, mage.cards.d.DragUnder.class)); cards.add(new SetCardInfo("Drogskol Shieldmate", 22, Rarity.UNCOMMON, mage.cards.d.DrogskolShieldmate.class)); - cards.add(new SetCardInfo("Dronepack Kindred", 148, Rarity.COMMON, mage.cards.d.DronepackKindred.class)); cards.add(new SetCardInfo("Drownyard Behemoth", 4, Rarity.UNCOMMON, mage.cards.d.DrownyardBehemoth.class)); cards.add(new SetCardInfo("Dusk Feaster", 88, Rarity.UNCOMMON, mage.cards.d.DuskFeaster.class)); cards.add(new SetCardInfo("Elder Deep-Fiend", 5, Rarity.RARE, mage.cards.e.ElderDeepFiend.class)); @@ -106,18 +102,14 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Emrakul's Influence", 157, Rarity.UNCOMMON, mage.cards.e.EmrakulsInfluence.class)); cards.add(new SetCardInfo("Emrakul, the Promised End", 6, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class)); cards.add(new SetCardInfo("Enlightened Maniac", 58, Rarity.COMMON, mage.cards.e.EnlightenedManiac.class)); - cards.add(new SetCardInfo("Erupting Dreadwolf", 142, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class)); cards.add(new SetCardInfo("Eternal Scourge", 7, Rarity.RARE, mage.cards.e.EternalScourge.class)); - cards.add(new SetCardInfo("Extricator of Flesh", 23, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfFlesh.class)); cards.add(new SetCardInfo("Extricator of Sin", 23, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfSin.class)); cards.add(new SetCardInfo("Exultant Cultist", 59, Rarity.COMMON, mage.cards.e.ExultantCultist.class)); cards.add(new SetCardInfo("Faith Unbroken", 24, Rarity.UNCOMMON, mage.cards.f.FaithUnbroken.class)); cards.add(new SetCardInfo("Faithbearer Paladin", 25, Rarity.COMMON, mage.cards.f.FaithbearerPaladin.class)); cards.add(new SetCardInfo("Falkenrath Reaver", 127, Rarity.COMMON, mage.cards.f.FalkenrathReaver.class)); - cards.add(new SetCardInfo("Fibrous Entangler", 174, Rarity.UNCOMMON, mage.cards.f.FibrousEntangler.class)); cards.add(new SetCardInfo("Field Creeper", 195, Rarity.COMMON, mage.cards.f.FieldCreeper.class)); cards.add(new SetCardInfo("Fiend Binder", 26, Rarity.COMMON, mage.cards.f.FiendBinder.class)); - cards.add(new SetCardInfo("Final Iteration", 56, Rarity.RARE, mage.cards.f.FinalIteration.class)); cards.add(new SetCardInfo("Fogwalker", 60, Rarity.COMMON, mage.cards.f.Fogwalker.class)); cards.add(new SetCardInfo("Fortune's Favor", 61, Rarity.UNCOMMON, mage.cards.f.FortunesFavor.class)); cards.add(new SetCardInfo("Foul Emissary", 158, Rarity.UNCOMMON, mage.cards.f.FoulEmissary.class)); @@ -136,7 +128,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Graf Rats", 91, Rarity.COMMON, mage.cards.g.GrafRats.class)); cards.add(new SetCardInfo("Grapple with the Past", 160, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class)); cards.add(new SetCardInfo("Grim Flayer", 184, Rarity.MYTHIC, mage.cards.g.GrimFlayer.class)); - cards.add(new SetCardInfo("Grisly Anglerfish", 63, Rarity.UNCOMMON, mage.cards.g.GrislyAnglerfish.class)); cards.add(new SetCardInfo("Grizzled Angler", 63, Rarity.UNCOMMON, mage.cards.g.GrizzledAngler.class)); cards.add(new SetCardInfo("Guardian of Pilgrims", 30, Rarity.COMMON, mage.cards.g.GuardianOfPilgrims.class)); cards.add(new SetCardInfo("Hamlet Captain", 161, Rarity.UNCOMMON, mage.cards.h.HamletCaptain.class)); @@ -146,7 +137,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Harmless Offering", 131, Rarity.RARE, mage.cards.h.HarmlessOffering.class)); cards.add(new SetCardInfo("Haunted Dead", 92, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class)); cards.add(new SetCardInfo("Heron's Grace Champion", 185, Rarity.RARE, mage.cards.h.HeronsGraceChampion.class)); - cards.add(new SetCardInfo("Howling Chorus", 168, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class)); cards.add(new SetCardInfo("Identity Thief", 64, Rarity.RARE, mage.cards.i.IdentityThief.class)); cards.add(new SetCardInfo("Impetuous Devils", 132, Rarity.RARE, mage.cards.i.ImpetuousDevils.class)); cards.add(new SetCardInfo("Imprisoned in the Moon", 65, Rarity.RARE, mage.cards.i.ImprisonedInTheMoon.class)); @@ -157,7 +147,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Ironwright's Cleansing", 32, Rarity.COMMON, mage.cards.i.IronwrightsCleansing.class)); cards.add(new SetCardInfo("Ishkanah, Grafwidow", 162, Rarity.MYTHIC, mage.cards.i.IshkanahGrafwidow.class)); cards.add(new SetCardInfo("It of the Horrid Swarm", 8, Rarity.COMMON, mage.cards.i.ItOfTheHorridSwarm.class)); - cards.add(new SetCardInfo("It That Rides as One", 33, Rarity.UNCOMMON, mage.cards.i.ItThatRidesAsOne.class)); cards.add(new SetCardInfo("Kessig Prowler", 163, Rarity.UNCOMMON, mage.cards.k.KessigProwler.class)); cards.add(new SetCardInfo("Laboratory Brute", 67, Rarity.COMMON, mage.cards.l.LaboratoryBrute.class)); cards.add(new SetCardInfo("Lashweed Lurker", 9, Rarity.UNCOMMON, mage.cards.l.LashweedLurker.class)); @@ -206,7 +195,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Shrill Howler", 168, Rarity.UNCOMMON, mage.cards.s.ShrillHowler.class)); cards.add(new SetCardInfo("Sigarda's Aid", 41, Rarity.RARE, mage.cards.s.SigardasAid.class)); cards.add(new SetCardInfo("Sigardian Priest", 42, Rarity.COMMON, mage.cards.s.SigardianPriest.class)); - cards.add(new SetCardInfo("Sinuous Predator", 163, Rarity.UNCOMMON, mage.cards.s.SinuousPredator.class)); cards.add(new SetCardInfo("Skirsdag Supplicant", 104, Rarity.COMMON, mage.cards.s.SkirsdagSupplicant.class)); cards.add(new SetCardInfo("Slayer's Cleaver", 198, Rarity.UNCOMMON, mage.cards.s.SlayersCleaver.class)); cards.add(new SetCardInfo("Smoldering Werewolf", 142, Rarity.UNCOMMON, mage.cards.s.SmolderingWerewolf.class)); @@ -244,8 +232,6 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Tree of Perdition", 109, Rarity.MYTHIC, mage.cards.t.TreeOfPerdition.class)); cards.add(new SetCardInfo("Turn Aside", 78, Rarity.COMMON, mage.cards.t.TurnAside.class)); cards.add(new SetCardInfo("Ulrich of the Krallenhorde", 191, Rarity.MYTHIC, mage.cards.u.UlrichOfTheKrallenhorde.class)); - cards.add(new SetCardInfo("Ulrich, Uncontested Alpha", 191, Rarity.MYTHIC, mage.cards.u.UlrichUncontestedAlpha.class)); - cards.add(new SetCardInfo("Ulvenwald Abomination", 175, Rarity.COMMON, mage.cards.u.UlvenwaldAbomination.class)); cards.add(new SetCardInfo("Ulvenwald Captive", 175, Rarity.COMMON, mage.cards.u.UlvenwaldCaptive.class)); cards.add(new SetCardInfo("Ulvenwald Observer", 176, Rarity.RARE, mage.cards.u.UlvenwaldObserver.class)); cards.add(new SetCardInfo("Unsubstantiate", 79, Rarity.UNCOMMON, mage.cards.u.Unsubstantiate.class)); diff --git a/Mage.Sets/src/mage/sets/EldritchMoonPromos.java b/Mage.Sets/src/mage/sets/EldritchMoonPromos.java index 8083a9daf47..32cae370100 100644 --- a/Mage.Sets/src/mage/sets/EldritchMoonPromos.java +++ b/Mage.Sets/src/mage/sets/EldritchMoonPromos.java @@ -20,7 +20,6 @@ public class EldritchMoonPromos extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Abolisher of Bloodlines", "111s", Rarity.RARE, mage.cards.a.AbolisherOfBloodlines.class)); cards.add(new SetCardInfo("Assembled Alphas", 117, Rarity.RARE, mage.cards.a.AssembledAlphas.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Assembled Alphas", "117s", Rarity.RARE, mage.cards.a.AssembledAlphas.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bedlam Reveler", "118s", Rarity.RARE, mage.cards.b.BedlamReveler.class)); @@ -42,7 +41,6 @@ public class EldritchMoonPromos extends ExpansionSet { cards.add(new SetCardInfo("Emrakul's Evangel", "156s", Rarity.RARE, mage.cards.e.EmrakulsEvangel.class)); cards.add(new SetCardInfo("Emrakul, the Promised End", "6s", Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class)); cards.add(new SetCardInfo("Eternal Scourge", "7s", Rarity.RARE, mage.cards.e.EternalScourge.class)); - cards.add(new SetCardInfo("Final Iteration", "56s", Rarity.RARE, mage.cards.f.FinalIteration.class)); cards.add(new SetCardInfo("Geier Reach Sanitarium", "203s", Rarity.RARE, mage.cards.g.GeierReachSanitarium.class)); cards.add(new SetCardInfo("Gisa and Geralf", "183s", Rarity.MYTHIC, mage.cards.g.GisaAndGeralf.class)); cards.add(new SetCardInfo("Gisela, the Broken Blade", "28s", Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class)); @@ -88,7 +86,6 @@ public class EldritchMoonPromos extends ExpansionSet { cards.add(new SetCardInfo("Thalia, Heretic Cathar", 46, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia, Heretic Cathar", "46s", Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tree of Perdition", "109s", Rarity.MYTHIC, mage.cards.t.TreeOfPerdition.class)); - cards.add(new SetCardInfo("Ulrich, Uncontested Alpha", "191s", Rarity.MYTHIC, mage.cards.u.UlrichUncontestedAlpha.class)); cards.add(new SetCardInfo("Ulrich of the Krallenhorde", "191s", Rarity.MYTHIC, mage.cards.u.UlrichOfTheKrallenhorde.class)); cards.add(new SetCardInfo("Ulvenwald Observer", 176, Rarity.RARE, mage.cards.u.UlvenwaldObserver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ulvenwald Observer", "176s", Rarity.RARE, mage.cards.u.UlvenwaldObserver.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index 811e772d46f..ac5e7899839 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -317,6 +317,8 @@ public final class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Obelisk of Undoing", 392, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Conscripts", 255, Rarity.COMMON, mage.cards.o.OrcishConscripts.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Farmer", 256, Rarity.COMMON, mage.cards.o.OrcishFarmer.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class, RETRO_ART)); cards.add(new SetCardInfo("Order of the Sacred Torch", 48, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class, RETRO_ART)); @@ -367,6 +369,7 @@ public final class FifthEdition extends ExpansionSet { cards.add(new SetCardInfo("Rod of Ruin", 396, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class, RETRO_ART)); cards.add(new SetCardInfo("Ruins of Trokair", 422, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class, RETRO_ART)); cards.add(new SetCardInfo("Sabretooth Tiger", 264, Rarity.COMMON, mage.cards.s.SabretoothTiger.class, RETRO_ART)); + cards.add(new SetCardInfo("Sacred Boon", 57, Rarity.UNCOMMON, mage.cards.s.SacredBoon.class, RETRO_ART)); cards.add(new SetCardInfo("Samite Healer", 58, Rarity.COMMON, mage.cards.s.SamiteHealer.class, RETRO_ART)); cards.add(new SetCardInfo("Sand Silos", 423, Rarity.RARE, mage.cards.s.SandSilos.class, RETRO_ART)); cards.add(new SetCardInfo("Scaled Wurm", 322, Rarity.COMMON, mage.cards.s.ScaledWurm.class, RETRO_ART)); diff --git a/Mage.Sets/src/mage/sets/FinalFantasy.java b/Mage.Sets/src/mage/sets/FinalFantasy.java index 04443dac090..08f1ff1161e 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasy.java +++ b/Mage.Sets/src/mage/sets/FinalFantasy.java @@ -56,12 +56,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Astrologian's Planisphere", 46, Rarity.RARE, mage.cards.a.AstrologiansPlanisphere.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Astrologian's Planisphere", 581, Rarity.RARE, mage.cards.a.AstrologiansPlanisphere.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Auron's Inspiration", 8, Rarity.UNCOMMON, mage.cards.a.AuronsInspiration.class)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 16, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 376, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 428, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bahamut, Warden of Light", 521, Rarity.RARE, mage.cards.b.BahamutWardenOfLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balamb Garden, Airborne", 272, Rarity.RARE, mage.cards.b.BalambGardenAirborne.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balamb Garden, Airborne", 354, Rarity.RARE, mage.cards.b.BalambGardenAirborne.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb Garden, SeeD Academy", 272, Rarity.RARE, mage.cards.b.BalambGardenSeeDAcademy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb Garden, SeeD Academy", 354, Rarity.RARE, mage.cards.b.BalambGardenSeeDAcademy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balamb T-Rexaur", 173, Rarity.COMMON, mage.cards.b.BalambTRexaur.class)); @@ -80,16 +74,12 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Battle Menu", 9, Rarity.UNCOMMON, mage.cards.b.BattleMenu.class)); cards.add(new SetCardInfo("Beatrix, Loyal General", 426, Rarity.RARE, mage.cards.b.BeatrixLoyalGeneral.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Beatrix, Loyal General", 554, Rarity.RARE, mage.cards.b.BeatrixLoyalGeneral.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Black Chocobo", 201, Rarity.UNCOMMON, mage.cards.b.BlackChocobo.class)); cards.add(new SetCardInfo("Black Mage's Rod", 90, Rarity.COMMON, mage.cards.b.BlackMagesRod.class)); cards.add(new SetCardInfo("Black Waltz No. 3", 214, Rarity.UNCOMMON, mage.cards.b.BlackWaltzNo3.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Black Waltz No. 3", 478, Rarity.UNCOMMON, mage.cards.b.BlackWaltzNo3.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blazing Bomb", 130, Rarity.COMMON, mage.cards.b.BlazingBomb.class)); cards.add(new SetCardInfo("Blitzball Shot", 176, Rarity.COMMON, mage.cards.b.BlitzballShot.class)); cards.add(new SetCardInfo("Blitzball", 254, Rarity.COMMON, mage.cards.b.Blitzball.class)); - cards.add(new SetCardInfo("Braska's Final Aeon", 104, Rarity.RARE, mage.cards.b.BraskasFinalAeon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braska's Final Aeon", 363, Rarity.RARE, mage.cards.b.BraskasFinalAeon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braska's Final Aeon", 448, Rarity.RARE, mage.cards.b.BraskasFinalAeon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Buster Sword", 255, Rarity.MYTHIC, mage.cards.b.BusterSword.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Buster Sword", 351, Rarity.MYTHIC, mage.cards.b.BusterSword.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cactuar", 177, Rarity.UNCOMMON, mage.cards.c.Cactuar.class)); @@ -100,12 +90,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Cecil, Dark Knight", 445, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cecil, Dark Knight", 525, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cecil, Dark Knight", 91, Rarity.RARE, mage.cards.c.CecilDarkKnight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 380, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 445, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 525, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cecil, Redeemed Paladin", 91, Rarity.RARE, mage.cards.c.CecilRedeemedPaladin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chaos, the Endless", 221, Rarity.UNCOMMON, mage.cards.c.ChaosTheEndless.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chaos, the Endless", 486, Rarity.UNCOMMON, mage.cards.c.ChaosTheEndless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Choco, Seeker of Paradise", 215, Rarity.RARE, mage.cards.c.ChocoSeekerOfParadise.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Choco, Seeker of Paradise", 479, Rarity.RARE, mage.cards.c.ChocoSeekerOfParadise.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Choco, Seeker of Paradise", 569, Rarity.RARE, mage.cards.c.ChocoSeekerOfParadise.class, NON_FULL_USE_VARIOUS)); @@ -152,14 +136,11 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Coliseum Behemoth", 181, Rarity.UNCOMMON, mage.cards.c.ColiseumBehemoth.class)); cards.add(new SetCardInfo("Combat Tutorial", 48, Rarity.COMMON, mage.cards.c.CombatTutorial.class)); cards.add(new SetCardInfo("Commune with Beavers", 182, Rarity.COMMON, mage.cards.c.CommuneWithBeavers.class)); - cards.add(new SetCardInfo("Cooking Campsite", 31, Rarity.UNCOMMON, mage.cards.c.CookingCampsite.class)); cards.add(new SetCardInfo("Coral Sword", 134, Rarity.UNCOMMON, mage.cards.c.CoralSword.class)); cards.add(new SetCardInfo("Cornered by Black Mages", 93, Rarity.COMMON, mage.cards.c.CorneredByBlackMages.class)); cards.add(new SetCardInfo("Crossroads Village", 276, Rarity.COMMON, mage.cards.c.CrossroadsVillage.class)); cards.add(new SetCardInfo("Crystal Fragments", 13, Rarity.UNCOMMON, mage.cards.c.CrystalFragments.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Crystal Fragments", 357, Rarity.UNCOMMON, mage.cards.c.CrystalFragments.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Crystallized Serah", 240, Rarity.RARE, mage.cards.c.CrystallizedSerah.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Crystallized Serah", 506, Rarity.RARE, mage.cards.c.CrystallizedSerah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Confidant", 334, Rarity.MYTHIC, mage.cards.d.DarkConfidant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Confidant", 94, Rarity.MYTHIC, mage.cards.d.DarkConfidant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Knight's Greatsword", 95, Rarity.UNCOMMON, mage.cards.d.DarkKnightsGreatsword.class)); @@ -188,9 +169,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Emet-Selch, Unsundered", 539, Rarity.MYTHIC, mage.cards.e.EmetSelchUnsundered.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Esper Origins", 185, Rarity.RARE, mage.cards.e.EsperOrigins.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Esper Origins", 370, Rarity.RARE, mage.cards.e.EsperOrigins.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Esper Terra", 245, Rarity.MYTHIC, mage.cards.e.EsperTerra.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Esper Terra", 323, Rarity.MYTHIC, mage.cards.e.EsperTerra.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Esper Terra", 511, Rarity.MYTHIC, mage.cards.e.EsperTerra.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ether", 53, Rarity.UNCOMMON, mage.cards.e.Ether.class)); cards.add(new SetCardInfo("Evil Reawakened", 98, Rarity.UNCOMMON, mage.cards.e.EvilReawakened.class)); cards.add(new SetCardInfo("Excalibur II", 257, Rarity.RARE, mage.cards.e.ExcaliburII.class, NON_FULL_USE_VARIOUS)); @@ -220,10 +198,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Gaelicat", 22, Rarity.COMMON, mage.cards.g.Gaelicat.class)); cards.add(new SetCardInfo("Gaius van Baelsar", 102, Rarity.UNCOMMON, mage.cards.g.GaiusVanBaelsar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gaius van Baelsar", 447, Rarity.UNCOMMON, mage.cards.g.GaiusVanBaelsar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Galian Beast", 125, Rarity.RARE, mage.cards.g.GalianBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Galian Beast", 383, Rarity.RARE, mage.cards.g.GalianBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Galian Beast", 454, Rarity.RARE, mage.cards.g.GalianBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Galian Beast", 528, Rarity.RARE, mage.cards.g.GalianBeast.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Galuf's Final Act", 186, Rarity.UNCOMMON, mage.cards.g.GalufsFinalAct.class)); cards.add(new SetCardInfo("Garland, Knight of Cornelia", 221, Rarity.UNCOMMON, mage.cards.g.GarlandKnightOfCornelia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Garland, Knight of Cornelia", 486, Rarity.UNCOMMON, mage.cards.g.GarlandKnightOfCornelia.class, NON_FULL_USE_VARIOUS)); @@ -252,10 +226,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Gran Pulse Ochu", 189, Rarity.COMMON, mage.cards.g.GranPulseOchu.class)); cards.add(new SetCardInfo("Guadosalam, Farplane Gateway", 281, Rarity.COMMON, mage.cards.g.GuadosalamFarplaneGateway.class)); cards.add(new SetCardInfo("Gysahl Greens", 190, Rarity.COMMON, mage.cards.g.GysahlGreens.class)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 218, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 394, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 483, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hades, Sorcerer of Eld", 539, Rarity.MYTHIC, mage.cards.h.HadesSorcererOfEld.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Haste Magic", 140, Rarity.COMMON, mage.cards.h.HasteMagic.class)); cards.add(new SetCardInfo("Hecteyes", 103, Rarity.COMMON, mage.cards.h.Hecteyes.class)); cards.add(new SetCardInfo("Hill Gigas", 141, Rarity.COMMON, mage.cards.h.HillGigas.class)); @@ -263,16 +233,8 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Hope Estheim", 396, Rarity.RARE, mage.cards.h.HopeEstheim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hope Estheim", 491, Rarity.RARE, mage.cards.h.HopeEstheim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hope Estheim", 541, Rarity.RARE, mage.cards.h.HopeEstheim.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hydaelyn, the Mothercrystal", 329, Rarity.RARE, mage.cards.h.HydaelynTheMothercrystal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hydaelyn, the Mothercrystal", 39, Rarity.RARE, mage.cards.h.HydaelynTheMothercrystal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hydaelyn, the Mothercrystal", 434, Rarity.RARE, mage.cards.h.HydaelynTheMothercrystal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ice Flan", 55, Rarity.COMMON, mage.cards.i.IceFlan.class)); cards.add(new SetCardInfo("Ice Magic", 56, Rarity.COMMON, mage.cards.i.IceMagic.class)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 133, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 318, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 385, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 458, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ifrit, Warden of Inferno", 530, Rarity.MYTHIC, mage.cards.i.IfritWardenOfInferno.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ignis Scientia", 227, Rarity.UNCOMMON, mage.cards.i.IgnisScientia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ignis Scientia", 492, Rarity.UNCOMMON, mage.cards.i.IgnisScientia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Il Mheg Pixie", 57, Rarity.UNCOMMON, mage.cards.i.IlMhegPixie.class)); @@ -315,11 +277,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Kefka, Court Mage", 398, Rarity.MYTHIC, mage.cards.k.KefkaCourtMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kefka, Court Mage", 496, Rarity.MYTHIC, mage.cards.k.KefkaCourtMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kefka, Court Mage", 543, Rarity.MYTHIC, mage.cards.k.KefkaCourtMage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kefka, Ruler of Ruin", 231, Rarity.MYTHIC, mage.cards.k.KefkaRulerOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kefka, Ruler of Ruin", 322, Rarity.MYTHIC, mage.cards.k.KefkaRulerOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kefka, Ruler of Ruin", 398, Rarity.MYTHIC, mage.cards.k.KefkaRulerOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kefka, Ruler of Ruin", 496, Rarity.MYTHIC, mage.cards.k.KefkaRulerOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kefka, Ruler of Ruin", 543, Rarity.MYTHIC, mage.cards.k.KefkaRulerOfRuin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kuja, Genome Sorcerer", 232, Rarity.RARE, mage.cards.k.KujaGenomeSorcerer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kuja, Genome Sorcerer", 399, Rarity.RARE, mage.cards.k.KujaGenomeSorcerer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kuja, Genome Sorcerer", 497, Rarity.RARE, mage.cards.k.KujaGenomeSorcerer.class, NON_FULL_USE_VARIOUS)); @@ -345,7 +302,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Machinist's Arsenal", 23, Rarity.RARE, mage.cards.m.MachinistsArsenal.class)); cards.add(new SetCardInfo("Magic Damper", 61, Rarity.COMMON, mage.cards.m.MagicDamper.class)); cards.add(new SetCardInfo("Magic Pot", 263, Rarity.COMMON, mage.cards.m.MagicPot.class)); - cards.add(new SetCardInfo("Magicked Card", 73, Rarity.UNCOMMON, mage.cards.m.MagickedCard.class)); cards.add(new SetCardInfo("Magitek Armor", 24, Rarity.UNCOMMON, mage.cards.m.MagitekArmor.class)); cards.add(new SetCardInfo("Magitek Infantry", 25, Rarity.COMMON, mage.cards.m.MagitekInfantry.class)); cards.add(new SetCardInfo("Magitek Scythe", 562, Rarity.RARE, mage.cards.m.MagitekScythe.class)); @@ -367,8 +323,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 575, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mysidian Elder", 145, Rarity.COMMON, mage.cards.m.MysidianElder.class)); cards.add(new SetCardInfo("Namazu Trader", 107, Rarity.COMMON, mage.cards.n.NamazuTrader.class)); - cards.add(new SetCardInfo("Neo Exdeath, Dimension's End", 220, Rarity.UNCOMMON, mage.cards.n.NeoExdeathDimensionsEnd.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Neo Exdeath, Dimension's End", 485, Rarity.UNCOMMON, mage.cards.n.NeoExdeathDimensionsEnd.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nibelheim Aflame", 146, Rarity.MYTHIC, mage.cards.n.NibelheimAflame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nibelheim Aflame", 339, Rarity.MYTHIC, mage.cards.n.NibelheimAflame.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ninja's Blades", 108, Rarity.RARE, mage.cards.n.NinjasBlades.class)); @@ -385,10 +339,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Phantom Train", 110, Rarity.UNCOMMON, mage.cards.p.PhantomTrain.class)); cards.add(new SetCardInfo("Phoenix Down", 29, Rarity.UNCOMMON, mage.cards.p.PhoenixDown.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Phoenix Down", 578, Rarity.UNCOMMON, mage.cards.p.PhoenixDown.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phoenix, Warden of Fire", 229, Rarity.RARE, mage.cards.p.PhoenixWardenOfFire.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phoenix, Warden of Fire", 397, Rarity.RARE, mage.cards.p.PhoenixWardenOfFire.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phoenix, Warden of Fire", 494, Rarity.RARE, mage.cards.p.PhoenixWardenOfFire.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phoenix, Warden of Fire", 542, Rarity.RARE, mage.cards.p.PhoenixWardenOfFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 295, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 296, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); @@ -460,11 +410,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Sephiroth, Fabled SOLDIER", 382, Rarity.MYTHIC, mage.cards.s.SephirothFabledSOLDIER.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Fabled SOLDIER", 451, Rarity.MYTHIC, mage.cards.s.SephirothFabledSOLDIER.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Fabled SOLDIER", 527, Rarity.MYTHIC, mage.cards.s.SephirothFabledSOLDIER.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 115, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 317, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 382, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 451, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sephiroth, One-Winged Angel", 527, Rarity.MYTHIC, mage.cards.s.SephirothOneWingedAngel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Planet's Heir", 505, Rarity.MYTHIC, mage.cards.s.SephirothPlanetsHeir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Planet's Heir", 553, Rarity.MYTHIC, mage.cards.s.SephirothPlanetsHeir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Serah Farron", 240, Rarity.RARE, mage.cards.s.SerahFarron.class, NON_FULL_USE_VARIOUS)); @@ -476,14 +421,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Shantotto, Tactician Magician", 507, Rarity.UNCOMMON, mage.cards.s.ShantottoTacticianMagician.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sharlayan, Nation of Scholars", 288, Rarity.COMMON, mage.cards.s.SharlayanNationOfScholars.class)); cards.add(new SetCardInfo("Shinra Reinforcements", 118, Rarity.COMMON, mage.cards.s.ShinraReinforcements.class)); - cards.add(new SetCardInfo("Shinryu, Transcendent Rival", 127, Rarity.RARE, mage.cards.s.ShinryuTranscendentRival.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shinryu, Transcendent Rival", 384, Rarity.RARE, mage.cards.s.ShinryuTranscendentRival.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shinryu, Transcendent Rival", 455, Rarity.RARE, mage.cards.s.ShinryuTranscendentRival.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shinryu, Transcendent Rival", 529, Rarity.RARE, mage.cards.s.ShinryuTranscendentRival.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shiva, Warden of Ice", 378, Rarity.RARE, mage.cards.s.ShivaWardenOfIce.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shiva, Warden of Ice", 438, Rarity.RARE, mage.cards.s.ShivaWardenOfIce.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shiva, Warden of Ice", 523, Rarity.RARE, mage.cards.s.ShivaWardenOfIce.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shiva, Warden of Ice", 58, Rarity.RARE, mage.cards.s.ShivaWardenOfIce.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sidequest: Card Collection", 73, Rarity.UNCOMMON, mage.cards.s.SidequestCardCollection.class)); cards.add(new SetCardInfo("Sidequest: Catch a Fish", 31, Rarity.UNCOMMON, mage.cards.s.SidequestCatchAFish.class)); cards.add(new SetCardInfo("Sidequest: Hunt the Mark", 119, Rarity.UNCOMMON, mage.cards.s.SidequestHuntTheMark.class, NON_FULL_USE_VARIOUS)); @@ -510,8 +447,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Stolen Uniform", 332, Rarity.UNCOMMON, mage.cards.s.StolenUniform.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stolen Uniform", 75, Rarity.UNCOMMON, mage.cards.s.StolenUniform.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stuck in Summoner's Sanctum", 76, Rarity.COMMON, mage.cards.s.StuckInSummonersSanctum.class)); - cards.add(new SetCardInfo("Summon: Alexander", 13, Rarity.UNCOMMON, mage.cards.s.SummonAlexander.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Alexander", 357, Rarity.UNCOMMON, mage.cards.s.SummonAlexander.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Anima", 120, Rarity.UNCOMMON, mage.cards.s.SummonAnima.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Anima", 364, Rarity.UNCOMMON, mage.cards.s.SummonAnima.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Bahamut", 1, Rarity.MYTHIC, mage.cards.s.SummonBahamut.class, NON_FULL_USE_VARIOUS)); @@ -520,8 +455,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Summon: Brynhildr", 366, Rarity.RARE, mage.cards.s.SummonBrynhildr.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Choco/Mog", 35, Rarity.COMMON, mage.cards.s.SummonChocoMog.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Choco/Mog", 358, Rarity.COMMON, mage.cards.s.SummonChocoMog.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Esper Maduin", 185, Rarity.RARE, mage.cards.s.SummonEsperMaduin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Summon: Esper Maduin", 370, Rarity.RARE, mage.cards.s.SummonEsperMaduin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Esper Ramuh", 161, Rarity.UNCOMMON, mage.cards.s.SummonEsperRamuh.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Esper Ramuh", 367, Rarity.UNCOMMON, mage.cards.s.SummonEsperRamuh.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Summon: Fat Chocobo", 202, Rarity.COMMON, mage.cards.s.SummonFatChocobo.class, NON_FULL_USE_VARIOUS)); @@ -569,8 +502,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("The Fire Crystal", 135, Rarity.RARE, mage.cards.t.TheFireCrystal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Fire Crystal", 337, Rarity.RARE, mage.cards.t.TheFireCrystal.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Gold Saucer", 279, Rarity.UNCOMMON, mage.cards.t.TheGoldSaucer.class)); - cards.add(new SetCardInfo("The Lord Master of Hell", 219, Rarity.UNCOMMON, mage.cards.t.TheLordMasterOfHell.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Lord Master of Hell", 484, Rarity.UNCOMMON, mage.cards.t.TheLordMasterOfHell.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Lunar Whale", 60, Rarity.RARE, mage.cards.t.TheLunarWhale.class)); cards.add(new SetCardInfo("The Masamune", 264, Rarity.RARE, mage.cards.t.TheMasamune.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Masamune", 353, Rarity.RARE, mage.cards.t.TheMasamune.class, NON_FULL_USE_VARIOUS)); @@ -599,10 +530,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Torgal, A Fine Hound", 345, Rarity.UNCOMMON, mage.cards.t.TorgalAFineHound.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Torgal, A Fine Hound", 474, Rarity.UNCOMMON, mage.cards.t.TorgalAFineHound.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Town Greeter", 209, Rarity.COMMON, mage.cards.t.TownGreeter.class)); - cards.add(new SetCardInfo("Trance Kuja, Fate Defied", 232, Rarity.RARE, mage.cards.t.TranceKujaFateDefied.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Trance Kuja, Fate Defied", 399, Rarity.RARE, mage.cards.t.TranceKujaFateDefied.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Trance Kuja, Fate Defied", 497, Rarity.RARE, mage.cards.t.TranceKujaFateDefied.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Trance Kuja, Fate Defied", 544, Rarity.RARE, mage.cards.t.TranceKujaFateDefied.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Travel the Overworld", 82, Rarity.UNCOMMON, mage.cards.t.TravelTheOverworld.class)); cards.add(new SetCardInfo("Traveling Chocobo", "551a", Rarity.MYTHIC, mage.cards.t.TravelingChocobo.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Traveling Chocobo", "551b", Rarity.MYTHIC, mage.cards.t.TravelingChocobo.class, NON_FULL_USE_VARIOUS)); @@ -622,8 +549,6 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("Ultima, Origin of Oblivion", 2, Rarity.RARE, mage.cards.u.UltimaOriginOfOblivion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ultima, Origin of Oblivion", 324, Rarity.RARE, mage.cards.u.UltimaOriginOfOblivion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ultima, Origin of Oblivion", 421, Rarity.RARE, mage.cards.u.UltimaOriginOfOblivion.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ultimecia, Omnipotent", 247, Rarity.UNCOMMON, mage.cards.u.UltimeciaOmnipotent.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ultimecia, Omnipotent", 513, Rarity.UNCOMMON, mage.cards.u.UltimeciaOmnipotent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ultimecia, Temporal Threat", 441, Rarity.RARE, mage.cards.u.UltimeciaTemporalThreat.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ultimecia, Temporal Threat", 556, Rarity.RARE, mage.cards.u.UltimeciaTemporalThreat.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ultimecia, Time Sorceress", 247, Rarity.UNCOMMON, mage.cards.u.UltimeciaTimeSorceress.class, NON_FULL_USE_VARIOUS)); @@ -662,15 +587,12 @@ public final class FinalFantasy extends ExpansionSet { cards.add(new SetCardInfo("White Auracite", 579, Rarity.COMMON, mage.cards.w.WhiteAuracite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("White Mage's Staff", 42, Rarity.COMMON, mage.cards.w.WhiteMagesStaff.class)); cards.add(new SetCardInfo("Windurst, Federation Center", 292, Rarity.COMMON, mage.cards.w.WindurstFederationCenter.class)); - cards.add(new SetCardInfo("World Champion, Celestial Weapon", 158, Rarity.UNCOMMON, mage.cards.w.WorldChampionCelestialWeapon.class)); cards.add(new SetCardInfo("World Map", 270, Rarity.COMMON, mage.cards.w.WorldMap.class)); cards.add(new SetCardInfo("Xande, Dark Mage", 516, Rarity.RARE, mage.cards.x.XandeDarkMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Xande, Dark Mage", 561, Rarity.RARE, mage.cards.x.XandeDarkMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Y'shtola Rhul", 443, Rarity.MYTHIC, mage.cards.y.YshtolaRhul.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Y'shtola Rhul", 577, Rarity.MYTHIC, mage.cards.y.YshtolaRhul.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Y'shtola Rhul", 86, Rarity.MYTHIC, mage.cards.y.YshtolaRhul.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yiazmat, Ultimate Mark", 119, Rarity.UNCOMMON, mage.cards.y.YiazmatUltimateMark.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yiazmat, Ultimate Mark", 453, Rarity.UNCOMMON, mage.cards.y.YiazmatUltimateMark.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("You're Not Alone", 44, Rarity.COMMON, mage.cards.y.YoureNotAlone.class)); cards.add(new SetCardInfo("Yuna, Hope of Spira", 250, Rarity.MYTHIC, mage.cards.y.YunaHopeOfSpira.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Yuna, Hope of Spira", 404, Rarity.MYTHIC, mage.cards.y.YunaHopeOfSpira.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java index 41c42f37a3e..3735cf1f758 100644 --- a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java +++ b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java @@ -88,6 +88,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Champions from Beyond", 11, Rarity.RARE, mage.cards.c.ChampionsFromBeyond.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos Warp", 291, Rarity.RARE, mage.cards.c.ChaosWarp.class)); cards.add(new SetCardInfo("Chasm Skulker", 262, Rarity.RARE, mage.cards.c.ChasmSkulker.class)); + cards.add(new SetCardInfo("Chocobo Camp", 462, Rarity.RARE, mage.cards.c.ChocoboCamp.class)); cards.add(new SetCardInfo("Chocobo Knights", 102, Rarity.RARE, mage.cards.c.ChocoboKnights.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chocobo Knights", 12, Rarity.RARE, mage.cards.c.ChocoboKnights.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Choked Estuary", 379, Rarity.RARE, mage.cards.c.ChokedEstuary.class)); @@ -170,6 +171,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Fight Rigging", 303, Rarity.RARE, mage.cards.f.FightRigging.class)); cards.add(new SetCardInfo("Final Judgment", 243, Rarity.MYTHIC, mage.cards.f.FinalJudgment.class)); cards.add(new SetCardInfo("Fire-Lit Thicket", 392, Rarity.RARE, mage.cards.f.FireLitThicket.class)); + cards.add(new SetCardInfo("Fishing Gear", 461, Rarity.RARE, mage.cards.f.FishingGear.class)); cards.add(new SetCardInfo("Flash Photography", 463, Rarity.RARE, mage.cards.f.FlashPhotography.class)); cards.add(new SetCardInfo("Flayer of the Hatebound", 293, Rarity.RARE, mage.cards.f.FlayerOfTheHatebound.class)); cards.add(new SetCardInfo("Flooded Grove", 393, Rarity.RARE, mage.cards.f.FloodedGrove.class)); @@ -186,6 +188,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("G'raha Tia, Scion Reborn", 222, Rarity.MYTHIC, mage.cards.g.GrahaTiaScionReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("G'raha Tia, Scion Reborn", 3, Rarity.MYTHIC, mage.cards.g.GrahaTiaScionReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Game Trail", 398, Rarity.RARE, mage.cards.g.GameTrail.class)); + cards.add(new SetCardInfo("Garland, Royal Kidnapper", 442, Rarity.RARE, mage.cards.g.GarlandRoyalKidnapper.class)); cards.add(new SetCardInfo("Gatta and Luzzu", 134, Rarity.RARE, mage.cards.g.GattaAndLuzzu.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gatta and Luzzu", 19, Rarity.RARE, mage.cards.g.GattaAndLuzzu.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gau, Feral Youth", 152, Rarity.RARE, mage.cards.g.GauFeralYouth.class, NON_FULL_USE_VARIOUS)); @@ -257,6 +260,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Maester Seymour", 160, Rarity.RARE, mage.cards.m.MaesterSeymour.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Maester Seymour", 68, Rarity.RARE, mage.cards.m.MaesterSeymour.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mask of Memory", 350, Rarity.UNCOMMON, mage.cards.m.MaskOfMemory.class)); + cards.add(new SetCardInfo("Mega Flare", 456, Rarity.RARE, mage.cards.m.MegaFlare.class)); cards.add(new SetCardInfo("Meteor Golem", 351, Rarity.UNCOMMON, mage.cards.m.MeteorGolem.class)); cards.add(new SetCardInfo("Millikin", 352, Rarity.UNCOMMON, mage.cards.m.Millikin.class)); cards.add(new SetCardInfo("Mind Stone", 353, Rarity.UNCOMMON, mage.cards.m.MindStone.class)); @@ -271,6 +275,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Nature's Lore", 311, Rarity.COMMON, mage.cards.n.NaturesLore.class)); cards.add(new SetCardInfo("Nesting Grounds", 408, Rarity.UNCOMMON, mage.cards.n.NestingGrounds.class)); cards.add(new SetCardInfo("Night's Whisper", 280, Rarity.COMMON, mage.cards.n.NightsWhisper.class)); + cards.add(new SetCardInfo("Noctis, Heir Apparent", 460, Rarity.RARE, mage.cards.n.NoctisHeirApparent.class)); cards.add(new SetCardInfo("Nomad Outpost", 409, Rarity.UNCOMMON, mage.cards.n.NomadOutpost.class)); cards.add(new SetCardInfo("O'aka, Traveling Merchant", 144, Rarity.RARE, mage.cards.o.OakaTravelingMerchant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("O'aka, Traveling Merchant", 39, Rarity.RARE, mage.cards.o.OakaTravelingMerchant.class, NON_FULL_USE_VARIOUS)); @@ -332,6 +337,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Secret Rendezvous", 218, Rarity.UNCOMMON, mage.cards.s.SecretRendezvous.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Secret Rendezvous", 219, Rarity.UNCOMMON, mage.cards.s.SecretRendezvous.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Secret Rendezvous", 253, Rarity.UNCOMMON, mage.cards.s.SecretRendezvous.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Seifer, Balamb Rival", 451, Rarity.RARE, mage.cards.s.SeiferBalambRival.class)); cards.add(new SetCardInfo("Sephiroth, Fallen Hero", 182, Rarity.RARE, mage.cards.s.SephirothFallenHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sephiroth, Fallen Hero", 92, Rarity.RARE, mage.cards.s.SephirothFallenHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sepulchral Primordial", 284, Rarity.RARE, mage.cards.s.SepulchralPrimordial.class)); @@ -363,6 +369,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Sphere Grid", 123, Rarity.RARE, mage.cards.s.SphereGrid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sphere Grid", 70, Rarity.RARE, mage.cards.s.SphereGrid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spire of Industry", 426, Rarity.RARE, mage.cards.s.SpireOfIndustry.class)); + cards.add(new SetCardInfo("Squall, Gunblade Duelist", 453, Rarity.RARE, mage.cards.s.SquallGunbladeDuelist.class)); cards.add(new SetCardInfo("Stitch Together", 286, Rarity.UNCOMMON, mage.cards.s.StitchTogether.class)); cards.add(new SetCardInfo("Stitcher's Supplier", 287, Rarity.UNCOMMON, mage.cards.s.StitchersSupplier.class)); cards.add(new SetCardInfo("Strago and Relm", 155, Rarity.RARE, mage.cards.s.StragoAndRelm.class, NON_FULL_USE_VARIOUS)); @@ -466,6 +473,7 @@ public final class FinalFantasyCommander extends ExpansionSet { cards.add(new SetCardInfo("Vincent, Vengeful Atoner", 64, Rarity.RARE, mage.cards.v.VincentVengefulAtoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vindicate", 330, Rarity.RARE, mage.cards.v.Vindicate.class)); cards.add(new SetCardInfo("Vineglimmer Snarl", 440, Rarity.RARE, mage.cards.v.VineglimmerSnarl.class)); + cards.add(new SetCardInfo("Vivi's Persistence", 458, Rarity.RARE, mage.cards.v.VivisPersistence.class)); cards.add(new SetCardInfo("Void Rend", 331, Rarity.RARE, mage.cards.v.VoidRend.class)); cards.add(new SetCardInfo("Wakka, Devoted Guardian", 190, Rarity.RARE, mage.cards.w.WakkaDevotedGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wakka, Devoted Guardian", 477, Rarity.RARE, mage.cards.w.WakkaDevotedGuardian.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/FromTheVaultTransform.java b/Mage.Sets/src/mage/sets/FromTheVaultTransform.java index 6bbc1f7e337..58d91a5f682 100644 --- a/Mage.Sets/src/mage/sets/FromTheVaultTransform.java +++ b/Mage.Sets/src/mage/sets/FromTheVaultTransform.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -21,33 +20,20 @@ public final class FromTheVaultTransform extends ExpansionSet { this.hasBasicLands = false; cards.add(new SetCardInfo("Archangel Avacyn", 1, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Arguel's Blood Fast", 2, Rarity.MYTHIC, mage.cards.a.ArguelsBloodFast.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 2, Rarity.MYTHIC, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Arlinn Kord", 3, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 3, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Bloodline Keeper", 4, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class)); - cards.add(new SetCardInfo("Lord of Lineage", 4, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Bruna, the Fading Light", 5, Rarity.MYTHIC, mage.cards.b.BrunaTheFadingLight.class)); cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "5b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 6, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 6, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Delver of Secrets", 7, Rarity.MYTHIC, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Insectile Aberration", 7, Rarity.MYTHIC, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Elbrus, the Binding Blade", 8, Rarity.MYTHIC, mage.cards.e.ElbrusTheBindingBlade.class)); - cards.add(new SetCardInfo("Withengar Unbound", 8, Rarity.MYTHIC, mage.cards.w.WithengarUnbound.class)); cards.add(new SetCardInfo("Garruk Relentless", 9, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); - cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 9, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); cards.add(new SetCardInfo("Gisela, the Broken Blade", 10, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class)); cards.add(new SetCardInfo("Huntmaster of the Fells", 11, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 11, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 12, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); - cards.add(new SetCardInfo("Jace, Telepath Unbound", 12, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Kytheon, Hero of Akros", 13, Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class)); - cards.add(new SetCardInfo("Gideon, Battle-Forged", 13, Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", 14, Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", 14, Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Nissa, Vastwood Seer", 15, Rarity.MYTHIC, mage.cards.n.NissaVastwoodSeer.class)); - cards.add(new SetCardInfo("Nissa, Sage Animist", 15, Rarity.MYTHIC, mage.cards.n.NissaSageAnimist.class)); } } diff --git a/Mage.Sets/src/mage/sets/HasCon2017.java b/Mage.Sets/src/mage/sets/HasCon2017.java index a8ef14cac47..f1341c2f45d 100644 --- a/Mage.Sets/src/mage/sets/HasCon2017.java +++ b/Mage.Sets/src/mage/sets/HasCon2017.java @@ -21,7 +21,6 @@ public final class HasCon2017 extends ExpansionSet { this.hasBasicLands = false; cards.add(new ExpansionSet.SetCardInfo("Grimlock, Dinobot Leader", 1, Rarity.MYTHIC, mage.cards.g.GrimlockDinobotLeader.class)); - cards.add(new ExpansionSet.SetCardInfo("Grimlock, Ferocious King", 1, Rarity.MYTHIC, mage.cards.g.GrimlockFerociousKing.class)); cards.add(new ExpansionSet.SetCardInfo("Sword of Dungeons & Dragons", 3, Rarity.MYTHIC, mage.cards.s.SwordOfDungeonsAndDragons.class)); } } diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index 93e4cdab640..c7772fdb108 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -264,6 +264,8 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Oath of Lim-Dul", 156, Rarity.RARE, mage.cards.o.OathOfLimDul.class, RETRO_ART)); cards.add(new SetCardInfo("Onyx Talisman", 331, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Conscripts", 206, Rarity.COMMON, mage.cards.o.OrcishConscripts.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Farmer", 207, Rarity.COMMON, mage.cards.o.OrcishFarmer.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Librarian", 209, Rarity.RARE, mage.cards.o.OrcishLibrarian.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Lumberjack", 210, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class, RETRO_ART)); @@ -300,6 +302,7 @@ public final class IceAge extends ExpansionSet { cards.add(new SetCardInfo("River Delta", 359, Rarity.RARE, mage.cards.r.RiverDelta.class, RETRO_ART)); cards.add(new SetCardInfo("Runed Arch", 334, Rarity.RARE, mage.cards.r.RunedArch.class, RETRO_ART)); cards.add(new SetCardInfo("Sabretooth Tiger", 215, Rarity.COMMON, mage.cards.s.SabretoothTiger.class, RETRO_ART)); + cards.add(new SetCardInfo("Sacred Boon", 50, Rarity.UNCOMMON, mage.cards.s.SacredBoon.class, RETRO_ART)); cards.add(new SetCardInfo("Scaled Wurm", 262, Rarity.COMMON, mage.cards.s.ScaledWurm.class, RETRO_ART)); cards.add(new SetCardInfo("Sea Spirit", 95, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class, RETRO_ART)); cards.add(new SetCardInfo("Seizures", 159, Rarity.COMMON, mage.cards.s.Seizures.class, RETRO_ART)); diff --git a/Mage.Sets/src/mage/sets/Innistrad.java b/Mage.Sets/src/mage/sets/Innistrad.java index d314bf52825..13615469bf5 100644 --- a/Mage.Sets/src/mage/sets/Innistrad.java +++ b/Mage.Sets/src/mage/sets/Innistrad.java @@ -48,7 +48,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Avacynian Priest", 4, Rarity.COMMON, mage.cards.a.AvacynianPriest.class)); cards.add(new SetCardInfo("Back from the Brink", 44, Rarity.RARE, mage.cards.b.BackFromTheBrink.class)); cards.add(new SetCardInfo("Balefire Dragon", 129, Rarity.MYTHIC, mage.cards.b.BalefireDragon.class)); - cards.add(new SetCardInfo("Bane of Hanweir", 145, Rarity.UNCOMMON, mage.cards.b.BaneOfHanweir.class)); cards.add(new SetCardInfo("Battleground Geist", 45, Rarity.UNCOMMON, mage.cards.b.BattlegroundGeist.class)); cards.add(new SetCardInfo("Bitterheart Witch", 88, Rarity.UNCOMMON, mage.cards.b.BitterheartWitch.class)); cards.add(new SetCardInfo("Blasphemous Act", 130, Rarity.RARE, mage.cards.b.BlasphemousAct.class)); @@ -124,8 +123,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Gallows Warden", 16, Rarity.UNCOMMON, mage.cards.g.GallowsWarden.class)); cards.add(new SetCardInfo("Galvanic Juggernaut", 222, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class)); cards.add(new SetCardInfo("Garruk Relentless", 181, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); - cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 181, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); - cards.add(new SetCardInfo("Gatstaf Howler", 182, Rarity.UNCOMMON, mage.cards.g.GatstafHowler.class)); cards.add(new SetCardInfo("Gatstaf Shepherd", 182, Rarity.UNCOMMON, mage.cards.g.GatstafShepherd.class)); cards.add(new SetCardInfo("Gavony Township", 239, Rarity.RARE, mage.cards.g.GavonyTownship.class)); cards.add(new SetCardInfo("Geist of Saint Traft", 213, Rarity.MYTHIC, mage.cards.g.GeistOfSaintTraft.class)); @@ -153,18 +150,13 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Heretic's Punishment", 147, Rarity.RARE, mage.cards.h.HereticsPunishment.class)); cards.add(new SetCardInfo("Hinterland Harbor", 241, Rarity.RARE, mage.cards.h.HinterlandHarbor.class)); cards.add(new SetCardInfo("Hollowhenge Scavenger", 188, Rarity.UNCOMMON, mage.cards.h.HollowhengeScavenger.class)); - cards.add(new SetCardInfo("Homicidal Brute", 47, Rarity.UNCOMMON, mage.cards.h.HomicidalBrute.class)); - cards.add(new SetCardInfo("Howlpack Alpha", 193, Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); - cards.add(new SetCardInfo("Howlpack of Estwald", 209, Rarity.COMMON, mage.cards.h.HowlpackOfEstwald.class)); cards.add(new SetCardInfo("Hysterical Blindness", 59, Rarity.COMMON, mage.cards.h.HystericalBlindness.class)); cards.add(new SetCardInfo("Infernal Plunge", 148, Rarity.COMMON, mage.cards.i.InfernalPlunge.class)); cards.add(new SetCardInfo("Inquisitor's Flail", 227, Rarity.UNCOMMON, mage.cards.i.InquisitorsFlail.class)); - cards.add(new SetCardInfo("Insectile Aberration", 51, Rarity.COMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Instigator Gang", 149, Rarity.RARE, mage.cards.i.InstigatorGang.class)); cards.add(new SetCardInfo("Intangible Virtue", 19, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); cards.add(new SetCardInfo("Into the Maw of Hell", 150, Rarity.UNCOMMON, mage.cards.i.IntoTheMawOfHell.class)); cards.add(new SetCardInfo("Invisible Stalker", 60, Rarity.UNCOMMON, mage.cards.i.InvisibleStalker.class)); - cards.add(new SetCardInfo("Ironfang", 168, Rarity.COMMON, mage.cards.i.Ironfang.class)); cards.add(new SetCardInfo("Island", 253, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); @@ -173,14 +165,11 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Kessig Wolf Run", 243, Rarity.RARE, mage.cards.k.KessigWolfRun.class)); cards.add(new SetCardInfo("Kessig Wolf", 151, Rarity.COMMON, mage.cards.k.KessigWolf.class)); cards.add(new SetCardInfo("Kindercatch", 190, Rarity.COMMON, mage.cards.k.Kindercatch.class)); - cards.add(new SetCardInfo("Krallenhorde Wantons", 185, Rarity.COMMON, mage.cards.k.KrallenhordeWantons.class)); cards.add(new SetCardInfo("Kruin Outlaw", 152, Rarity.RARE, mage.cards.k.KruinOutlaw.class)); cards.add(new SetCardInfo("Laboratory Maniac", 61, Rarity.RARE, mage.cards.l.LaboratoryManiac.class)); cards.add(new SetCardInfo("Lantern Spirit", 62, Rarity.UNCOMMON, mage.cards.l.LanternSpirit.class)); cards.add(new SetCardInfo("Liliana of the Veil", 105, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class)); - cards.add(new SetCardInfo("Lord of Lineage", 90, Rarity.RARE, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Lost in the Mist", 63, Rarity.COMMON, mage.cards.l.LostInTheMist.class)); - cards.add(new SetCardInfo("Ludevic's Abomination", 64, Rarity.RARE, mage.cards.l.LudevicsAbomination.class)); cards.add(new SetCardInfo("Ludevic's Test Subject", 64, Rarity.RARE, mage.cards.l.LudevicsTestSubject.class)); cards.add(new SetCardInfo("Lumberknot", 191, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class)); cards.add(new SetCardInfo("Make a Wish", 192, Rarity.UNCOMMON, mage.cards.m.MakeAWish.class)); @@ -194,7 +183,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Mayor of Avabruck", 193, Rarity.RARE, mage.cards.m.MayorOfAvabruck.class)); cards.add(new SetCardInfo("Memory's Journey", 66, Rarity.UNCOMMON, mage.cards.m.MemorysJourney.class)); cards.add(new SetCardInfo("Mentor of the Meek", 21, Rarity.RARE, mage.cards.m.MentorOfTheMeek.class)); - cards.add(new SetCardInfo("Merciless Predator", 159, Rarity.UNCOMMON, mage.cards.m.MercilessPredator.class)); cards.add(new SetCardInfo("Midnight Haunting", 22, Rarity.UNCOMMON, mage.cards.m.MidnightHaunting.class)); cards.add(new SetCardInfo("Mikaeus, the Lunarch", 23, Rarity.MYTHIC, mage.cards.m.MikaeusTheLunarch.class)); cards.add(new SetCardInfo("Mindshrieker", 67, Rarity.RARE, mage.cards.m.Mindshrieker.class)); @@ -217,7 +205,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Night Revelers", 153, Rarity.COMMON, mage.cards.n.NightRevelers.class)); cards.add(new SetCardInfo("Night Terrors", 111, Rarity.COMMON, mage.cards.n.NightTerrors.class)); cards.add(new SetCardInfo("Nightbird's Clutches", 154, Rarity.COMMON, mage.cards.n.NightbirdsClutches.class)); - cards.add(new SetCardInfo("Nightfall Predator", 176, Rarity.RARE, mage.cards.n.NightfallPredator.class)); cards.add(new SetCardInfo("Olivia Voldaren", 215, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class)); cards.add(new SetCardInfo("One-Eyed Scarecrow", 230, Rarity.COMMON, mage.cards.o.OneEyedScarecrow.class)); cards.add(new SetCardInfo("Orchard Spirit", 198, Rarity.COMMON, mage.cards.o.OrchardSpirit.class)); @@ -233,7 +220,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Rage Thrower", 157, Rarity.UNCOMMON, mage.cards.r.RageThrower.class)); cards.add(new SetCardInfo("Rakish Heir", 158, Rarity.UNCOMMON, mage.cards.r.RakishHeir.class)); cards.add(new SetCardInfo("Rally the Peasants", 28, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class)); - cards.add(new SetCardInfo("Rampaging Werewolf", 165, Rarity.COMMON, mage.cards.r.RampagingWerewolf.class)); cards.add(new SetCardInfo("Ranger's Guile", 201, Rarity.COMMON, mage.cards.r.RangersGuile.class)); cards.add(new SetCardInfo("Reaper from the Abyss", 112, Rarity.MYTHIC, mage.cards.r.ReaperFromTheAbyss.class)); cards.add(new SetCardInfo("Rebuke", 29, Rarity.COMMON, mage.cards.r.Rebuke.class)); @@ -270,7 +256,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Spider Spawning", 203, Rarity.UNCOMMON, mage.cards.s.SpiderSpawning.class)); cards.add(new SetCardInfo("Spidery Grasp", 204, Rarity.COMMON, mage.cards.s.SpideryGrasp.class)); cards.add(new SetCardInfo("Splinterfright", 205, Rarity.RARE, mage.cards.s.Splinterfright.class)); - cards.add(new SetCardInfo("Stalking Vampire", 114, Rarity.UNCOMMON, mage.cards.s.StalkingVampire.class)); cards.add(new SetCardInfo("Stensia Bloodhall", 247, Rarity.RARE, mage.cards.s.StensiaBloodhall.class)); cards.add(new SetCardInfo("Stitched Drake", 80, Rarity.COMMON, mage.cards.s.StitchedDrake.class)); cards.add(new SetCardInfo("Stitcher's Apprentice", 81, Rarity.COMMON, mage.cards.s.StitchersApprentice.class)); @@ -282,9 +267,7 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 256, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 257, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 258, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Terror of Kruin Pass", 152, Rarity.RARE, mage.cards.t.TerrorOfKruinPass.class)); cards.add(new SetCardInfo("Think Twice", 83, Rarity.COMMON, mage.cards.t.ThinkTwice.class)); - cards.add(new SetCardInfo("Thraben Militia", 38, Rarity.COMMON, mage.cards.t.ThrabenMilitia.class)); cards.add(new SetCardInfo("Thraben Purebloods", 37, Rarity.COMMON, mage.cards.t.ThrabenPurebloods.class)); cards.add(new SetCardInfo("Thraben Sentry", 38, Rarity.COMMON, mage.cards.t.ThrabenSentry.class)); cards.add(new SetCardInfo("Tormented Pariah", 165, Rarity.COMMON, mage.cards.t.TormentedPariah.class)); @@ -296,11 +279,9 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Tribute to Hunger", 119, Rarity.UNCOMMON, mage.cards.t.TributeToHunger.class)); cards.add(new SetCardInfo("Typhoid Rats", 120, Rarity.COMMON, mage.cards.t.TyphoidRats.class)); cards.add(new SetCardInfo("Ulvenwald Mystics", 208, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMystics.class)); - cards.add(new SetCardInfo("Ulvenwald Primordials", 208, Rarity.UNCOMMON, mage.cards.u.UlvenwaldPrimordials.class)); cards.add(new SetCardInfo("Unbreathing Horde", 121, Rarity.RARE, mage.cards.u.UnbreathingHorde.class)); cards.add(new SetCardInfo("Unburial Rites", 122, Rarity.UNCOMMON, mage.cards.u.UnburialRites.class)); cards.add(new SetCardInfo("Undead Alchemist", 84, Rarity.RARE, mage.cards.u.UndeadAlchemist.class)); - cards.add(new SetCardInfo("Unholy Fiend", 8, Rarity.UNCOMMON, mage.cards.u.UnholyFiend.class)); cards.add(new SetCardInfo("Unruly Mob", 39, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); cards.add(new SetCardInfo("Urgent Exorcism", 40, Rarity.COMMON, mage.cards.u.UrgentExorcism.class)); cards.add(new SetCardInfo("Vampire Interloper", 123, Rarity.COMMON, mage.cards.v.VampireInterloper.class)); @@ -312,7 +293,6 @@ public final class Innistrad extends ExpansionSet { cards.add(new SetCardInfo("Villagers of Estwald", 209, Rarity.COMMON, mage.cards.v.VillagersOfEstwald.class)); cards.add(new SetCardInfo("Voiceless Spirit", 42, Rarity.COMMON, mage.cards.v.VoicelessSpirit.class)); cards.add(new SetCardInfo("Walking Corpse", 126, Rarity.COMMON, mage.cards.w.WalkingCorpse.class)); - cards.add(new SetCardInfo("Wildblood Pack", 149, Rarity.RARE, mage.cards.w.WildbloodPack.class)); cards.add(new SetCardInfo("Witchbane Orb", 236, Rarity.RARE, mage.cards.w.WitchbaneOrb.class)); cards.add(new SetCardInfo("Wooden Stake", 237, Rarity.COMMON, mage.cards.w.WoodenStake.class)); cards.add(new SetCardInfo("Woodland Cemetery", 249, Rarity.RARE, mage.cards.w.WoodlandCemetery.class)); diff --git a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java index d2e0b5fbf70..4cf85b4fdca 100644 --- a/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java +++ b/Mage.Sets/src/mage/sets/InnistradCrimsonVow.java @@ -46,7 +46,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Alchemist's Retrieval", 47, Rarity.COMMON, mage.cards.a.AlchemistsRetrieval.class)); cards.add(new SetCardInfo("Alluring Suitor", 141, Rarity.UNCOMMON, mage.cards.a.AlluringSuitor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Alluring Suitor", 300, Rarity.UNCOMMON, mage.cards.a.AlluringSuitor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ancestor's Embrace", 22, Rarity.COMMON, mage.cards.a.AncestorsEmbrace.class)); cards.add(new SetCardInfo("Ancestral Anger", 142, Rarity.COMMON, mage.cards.a.AncestralAnger.class)); cards.add(new SetCardInfo("Ancient Lumberknot", 230, Rarity.UNCOMMON, mage.cards.a.AncientLumberknot.class)); cards.add(new SetCardInfo("Angelic Quartermaster", 2, Rarity.UNCOMMON, mage.cards.a.AngelicQuartermaster.class)); @@ -60,12 +59,10 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Avabruck Caretaker", 187, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avabruck Caretaker", 384, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ballista Watcher", 143, Rarity.UNCOMMON, mage.cards.b.BallistaWatcher.class)); - cards.add(new SetCardInfo("Ballista Wielder", 143, Rarity.UNCOMMON, mage.cards.b.BallistaWielder.class)); cards.add(new SetCardInfo("Belligerent Guest", 144, Rarity.COMMON, mage.cards.b.BelligerentGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Belligerent Guest", 301, Rarity.COMMON, mage.cards.b.BelligerentGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Binding Geist", 48, Rarity.COMMON, mage.cards.b.BindingGeist.class)); cards.add(new SetCardInfo("Biolume Egg", 49, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class)); - cards.add(new SetCardInfo("Biolume Serpent", 49, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class)); cards.add(new SetCardInfo("Bleed Dry", 94, Rarity.COMMON, mage.cards.b.BleedDry.class)); cards.add(new SetCardInfo("Blood Fountain", 95, Rarity.COMMON, mage.cards.b.BloodFountain.class)); cards.add(new SetCardInfo("Blood Hypnotist", 145, Rarity.UNCOMMON, mage.cards.b.BloodHypnotist.class, NON_FULL_USE_VARIOUS)); @@ -73,15 +70,8 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Blood Petal Celebrant", 146, Rarity.COMMON, mage.cards.b.BloodPetalCelebrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Petal Celebrant", 303, Rarity.COMMON, mage.cards.b.BloodPetalCelebrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Servitor", 252, Rarity.COMMON, mage.cards.b.BloodServitor.class)); - cards.add(new SetCardInfo("Bloodbat Summoner", 137, Rarity.RARE, mage.cards.b.BloodbatSummoner.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodbat Summoner", 298, Rarity.RARE, mage.cards.b.BloodbatSummoner.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodbat Summoner", 338, Rarity.RARE, mage.cards.b.BloodbatSummoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodcrazed Socialite", 288, Rarity.COMMON, mage.cards.b.BloodcrazedSocialite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodcrazed Socialite", 96, Rarity.COMMON, mage.cards.b.BloodcrazedSocialite.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsoaked Reveler", 128, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsoaked Reveler", 295, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsworn Knight", 289, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsworn Knight", 97, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsworn Squire", 289, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodsworn Squire", 97, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodtithe Harvester", 232, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, NON_FULL_USE_VARIOUS)); @@ -89,20 +79,15 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Bloodvial Purveyor", 290, Rarity.RARE, mage.cards.b.BloodvialPurveyor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodvial Purveyor", 98, Rarity.RARE, mage.cards.b.BloodvialPurveyor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloody Betrayal", 147, Rarity.COMMON, mage.cards.b.BloodyBetrayal.class)); - cards.add(new SetCardInfo("Blossom-Clad Werewolf", 226, Rarity.COMMON, mage.cards.b.BlossomCladWerewolf.class)); cards.add(new SetCardInfo("Boarded Window", 253, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class)); cards.add(new SetCardInfo("Bramble Armor", 188, Rarity.COMMON, mage.cards.b.BrambleArmor.class)); cards.add(new SetCardInfo("Bramble Wurm", 189, Rarity.UNCOMMON, mage.cards.b.BrambleWurm.class)); cards.add(new SetCardInfo("Bride's Gown", 4, Rarity.UNCOMMON, mage.cards.b.BridesGown.class)); cards.add(new SetCardInfo("Brine Comber", 233, Rarity.UNCOMMON, mage.cards.b.BrineComber.class)); - cards.add(new SetCardInfo("Brinebound Gift", 233, Rarity.UNCOMMON, mage.cards.b.BrineboundGift.class)); cards.add(new SetCardInfo("By Invitation Only", 346, Rarity.RARE, mage.cards.b.ByInvitationOnly.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("By Invitation Only", 5, Rarity.RARE, mage.cards.b.ByInvitationOnly.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cackling Culprit", 28, Rarity.UNCOMMON, mage.cards.c.CacklingCulprit.class)); cards.add(new SetCardInfo("Cartographer's Survey", 190, Rarity.UNCOMMON, mage.cards.c.CartographersSurvey.class)); - cards.add(new SetCardInfo("Catapult Captain", 99, Rarity.UNCOMMON, mage.cards.c.CatapultCaptain.class)); cards.add(new SetCardInfo("Catapult Fodder", 99, Rarity.UNCOMMON, mage.cards.c.CatapultFodder.class)); - cards.add(new SetCardInfo("Catlike Curiosity", 69, Rarity.UNCOMMON, mage.cards.c.CatlikeCuriosity.class)); cards.add(new SetCardInfo("Cemetery Desecrator", 100, Rarity.MYTHIC, mage.cards.c.CemeteryDesecrator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cemetery Desecrator", 366, Rarity.MYTHIC, mage.cards.c.CemeteryDesecrator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cemetery Gatekeeper", 148, Rarity.MYTHIC, mage.cards.c.CemeteryGatekeeper.class, NON_FULL_USE_VARIOUS)); @@ -120,10 +105,8 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Change of Fortune", 375, Rarity.RARE, mage.cards.c.ChangeOfFortune.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Child of the Pack", 234, Rarity.UNCOMMON, mage.cards.c.ChildOfThePack.class)); cards.add(new SetCardInfo("Chill of the Grave", 51, Rarity.COMMON, mage.cards.c.ChillOfTheGrave.class)); - cards.add(new SetCardInfo("Cipherbound Spirit", 79, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class)); cards.add(new SetCardInfo("Circle of Confinement", 329, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Circle of Confinement", 7, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Clever Distraction", 9, Rarity.UNCOMMON, mage.cards.c.CleverDistraction.class)); cards.add(new SetCardInfo("Cloaked Cadet", 192, Rarity.UNCOMMON, mage.cards.c.CloakedCadet.class)); cards.add(new SetCardInfo("Cobbled Lancer", 52, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class)); cards.add(new SetCardInfo("Concealing Curtains", 101, Rarity.RARE, mage.cards.c.ConcealingCurtains.class, NON_FULL_USE_VARIOUS)); @@ -144,18 +127,13 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dawnhart Disciple", 196, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class)); cards.add(new SetCardInfo("Dawnhart Geist", 8, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class)); cards.add(new SetCardInfo("Daybreak Combatants", 153, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); - cards.add(new SetCardInfo("Deadly Dancer", 141, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deadly Dancer", 300, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deathcap Glade", 261, Rarity.RARE, mage.cards.d.DeathcapGlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deathcap Glade", 281, Rarity.RARE, mage.cards.d.DeathcapGlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Bargain", 103, Rarity.RARE, mage.cards.d.DemonicBargain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Bargain", 368, Rarity.RARE, mage.cards.d.DemonicBargain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Depraved Harvester", 104, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Desperate Farmer", 104, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); cards.add(new SetCardInfo("Dig Up", 197, Rarity.RARE, mage.cards.d.DigUp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dig Up", 387, Rarity.RARE, mage.cards.d.DigUp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Anarchist", 181, Rarity.MYTHIC, mage.cards.d.DireStrainAnarchist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Anarchist", 382, Rarity.MYTHIC, mage.cards.d.DireStrainAnarchist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diregraf Scavenger", 105, Rarity.COMMON, mage.cards.d.DiregrafScavenger.class)); cards.add(new SetCardInfo("Distracting Geist", 9, Rarity.UNCOMMON, mage.cards.d.DistractingGeist.class)); cards.add(new SetCardInfo("Diver Skaab", 56, Rarity.UNCOMMON, mage.cards.d.DiverSkaab.class)); @@ -166,8 +144,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dominating Vampire", 407, Rarity.RARE, mage.cards.d.DominatingVampire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doomed Dissenter", 106, Rarity.COMMON, mage.cards.d.DoomedDissenter.class)); cards.add(new SetCardInfo("Dormant Grove", 198, Rarity.UNCOMMON, mage.cards.d.DormantGrove.class)); - cards.add(new SetCardInfo("Dorothea's Retribution", 235, Rarity.RARE, mage.cards.d.DorotheasRetribution.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dorothea's Retribution", 322, Rarity.RARE, mage.cards.d.DorotheasRetribution.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 235, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 322, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dread Fugue", 107, Rarity.UNCOMMON, mage.cards.d.DreadFugue.class)); @@ -178,13 +154,9 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Dreamroot Cascade", 282, Rarity.RARE, mage.cards.d.DreamrootCascade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dreamshackle Geist", 358, Rarity.RARE, mage.cards.d.DreamshackleGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dreamshackle Geist", 58, Rarity.RARE, mage.cards.d.DreamshackleGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Drogskol Armaments", 10, Rarity.COMMON, mage.cards.d.DrogskolArmaments.class)); cards.add(new SetCardInfo("Drogskol Infantry", 10, Rarity.COMMON, mage.cards.d.DrogskolInfantry.class)); cards.add(new SetCardInfo("Dying to Serve", 109, Rarity.RARE, mage.cards.d.DyingToServe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dying to Serve", 370, Rarity.RARE, mage.cards.d.DyingToServe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 236, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 311, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 341, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Edgar's Awakening", 110, Rarity.UNCOMMON, mage.cards.e.EdgarsAwakening.class)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 236, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 311, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class, NON_FULL_USE_VARIOUS)); @@ -204,7 +176,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Falkenrath Forebear", 334, Rarity.RARE, mage.cards.f.FalkenrathForebear.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fear of Death", 59, Rarity.COMMON, mage.cards.f.FearOfDeath.class)); cards.add(new SetCardInfo("Fearful Villager", 157, Rarity.COMMON, mage.cards.f.FearfulVillager.class)); - cards.add(new SetCardInfo("Fearsome Werewolf", 157, Rarity.COMMON, mage.cards.f.FearsomeWerewolf.class)); cards.add(new SetCardInfo("Fell Stinger", 112, Rarity.UNCOMMON, mage.cards.f.FellStinger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fell Stinger", 406, Rarity.UNCOMMON, mage.cards.f.FellStinger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fierce Retribution", 13, Rarity.COMMON, mage.cards.f.FierceRetribution.class)); @@ -222,14 +193,11 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Geistlight Snare", 60, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geralf, Visionary Stitcher", 319, Rarity.RARE, mage.cards.g.GeralfVisionaryStitcher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geralf, Visionary Stitcher", 61, Rarity.RARE, mage.cards.g.GeralfVisionaryStitcher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghastly Mimicry", 361, Rarity.RARE, mage.cards.g.GhastlyMimicry.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghastly Mimicry", 68, Rarity.RARE, mage.cards.g.GhastlyMimicry.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gift of Fangs", 113, Rarity.COMMON, mage.cards.g.GiftOfFangs.class)); cards.add(new SetCardInfo("Glorious Sunrise", 200, Rarity.RARE, mage.cards.g.GloriousSunrise.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glorious Sunrise", 388, Rarity.RARE, mage.cards.g.GloriousSunrise.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gluttonous Guest", 114, Rarity.COMMON, mage.cards.g.GluttonousGuest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gluttonous Guest", 292, Rarity.COMMON, mage.cards.g.GluttonousGuest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gnarled Grovestrider", 198, Rarity.UNCOMMON, mage.cards.g.GnarledGrovestrider.class)); cards.add(new SetCardInfo("Graf Reaver", 115, Rarity.RARE, mage.cards.g.GrafReaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Graf Reaver", 371, Rarity.RARE, mage.cards.g.GrafReaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grisly Ritual", 116, Rarity.COMMON, mage.cards.g.GrislyRitual.class)); @@ -238,7 +206,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Groom's Finery", 117, Rarity.UNCOMMON, mage.cards.g.GroomsFinery.class)); cards.add(new SetCardInfo("Gryff Rider", 15, Rarity.COMMON, mage.cards.g.GryffRider.class)); cards.add(new SetCardInfo("Gryffwing Cavalry", 16, Rarity.UNCOMMON, mage.cards.g.GryffwingCavalry.class)); - cards.add(new SetCardInfo("Gutter Shortcut", 62, Rarity.UNCOMMON, mage.cards.g.GutterShortcut.class)); cards.add(new SetCardInfo("Gutter Skulker", 62, Rarity.UNCOMMON, mage.cards.g.GutterSkulker.class)); cards.add(new SetCardInfo("Halana and Alena, Partners", 239, Rarity.RARE, mage.cards.h.HalanaAndAlenaPartners.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Halana and Alena, Partners", 325, Rarity.RARE, mage.cards.h.HalanaAndAlenaPartners.class, NON_FULL_USE_VARIOUS)); @@ -246,24 +213,16 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Hallowed Haunting", 349, Rarity.MYTHIC, mage.cards.h.HallowedHaunting.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hamlet Vanguard", 201, Rarity.RARE, mage.cards.h.HamletVanguard.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hamlet Vanguard", 389, Rarity.RARE, mage.cards.h.HamletVanguard.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hauken's Insight", 320, Rarity.MYTHIC, mage.cards.h.HaukensInsight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hauken's Insight", 332, Rarity.MYTHIC, mage.cards.h.HaukensInsight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hauken's Insight", 65, Rarity.MYTHIC, mage.cards.h.HaukensInsight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Headless Rider", 118, Rarity.RARE, mage.cards.h.HeadlessRider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Headless Rider", 372, Rarity.RARE, mage.cards.h.HeadlessRider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Henrika Domnathi", 119, Rarity.MYTHIC, mage.cards.h.HenrikaDomnathi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Henrika Domnathi", 293, Rarity.MYTHIC, mage.cards.h.HenrikaDomnathi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Henrika Domnathi", 335, Rarity.MYTHIC, mage.cards.h.HenrikaDomnathi.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Henrika, Infernal Seer", 119, Rarity.MYTHIC, mage.cards.h.HenrikaInfernalSeer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Henrika, Infernal Seer", 293, Rarity.MYTHIC, mage.cards.h.HenrikaInfernalSeer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Henrika, Infernal Seer", 335, Rarity.MYTHIC, mage.cards.h.HenrikaInfernalSeer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hero's Downfall", 120, Rarity.UNCOMMON, mage.cards.h.HerosDownfall.class)); cards.add(new SetCardInfo("Heron of Hope", 18, Rarity.COMMON, mage.cards.h.HeronOfHope.class)); cards.add(new SetCardInfo("Heron-Blessed Geist", 19, Rarity.COMMON, mage.cards.h.HeronBlessedGeist.class)); cards.add(new SetCardInfo("Hiveheart Shaman", 202, Rarity.RARE, mage.cards.h.HiveheartShaman.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hiveheart Shaman", 390, Rarity.RARE, mage.cards.h.HiveheartShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 187, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 384, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Honeymoon Hearse", 160, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class)); cards.add(new SetCardInfo("Honored Heirloom", 257, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class)); cards.add(new SetCardInfo("Hookhand Mariner", 203, Rarity.COMMON, mage.cards.h.HookhandMariner.class)); @@ -271,8 +230,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Hopeful Initiate", 350, Rarity.RARE, mage.cards.h.HopefulInitiate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Howling Moon", 204, Rarity.RARE, mage.cards.h.HowlingMoon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Howling Moon", 391, Rarity.RARE, mage.cards.h.HowlingMoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Howlpack Avenger", 162, Rarity.RARE, mage.cards.h.HowlpackAvenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Howlpack Avenger", 378, Rarity.RARE, mage.cards.h.HowlpackAvenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Howlpack Piper", 205, Rarity.RARE, mage.cards.h.HowlpackPiper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Howlpack Piper", 392, Rarity.RARE, mage.cards.h.HowlpackPiper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hullbreaker Horror", 359, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, NON_FULL_USE_VARIOUS)); @@ -281,7 +238,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Ill-Tempered Loner", 162, Rarity.RARE, mage.cards.i.IllTemperedLoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ill-Tempered Loner", 378, Rarity.RARE, mage.cards.i.IllTemperedLoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infestation Expert", 206, Rarity.UNCOMMON, mage.cards.i.InfestationExpert.class)); - cards.add(new SetCardInfo("Infested Werewolf", 206, Rarity.UNCOMMON, mage.cards.i.InfestedWerewolf.class)); cards.add(new SetCardInfo("Innocent Traveler", 121, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Innocent Traveler", 294, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Innocent Traveler", 336, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class, NON_FULL_USE_VARIOUS)); @@ -298,8 +254,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Jacob Hauken, Inspector", 320, Rarity.MYTHIC, mage.cards.j.JacobHaukenInspector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jacob Hauken, Inspector", 332, Rarity.MYTHIC, mage.cards.j.JacobHaukenInspector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jacob Hauken, Inspector", 65, Rarity.MYTHIC, mage.cards.j.JacobHaukenInspector.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Katilda's Rising Dawn", 21, Rarity.RARE, mage.cards.k.KatildasRisingDawn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Katilda's Rising Dawn", 317, Rarity.RARE, mage.cards.k.KatildasRisingDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katilda, Dawnhart Martyr", 21, Rarity.RARE, mage.cards.k.KatildaDawnhartMartyr.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katilda, Dawnhart Martyr", 317, Rarity.RARE, mage.cards.k.KatildaDawnhartMartyr.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kaya, Geist Hunter", 240, Rarity.MYTHIC, mage.cards.k.KayaGeistHunter.class, NON_FULL_USE_VARIOUS)); @@ -308,24 +262,16 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Kessig Wolfrider", 165, Rarity.RARE, mage.cards.k.KessigWolfrider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kessig Wolfrider", 379, Rarity.RARE, mage.cards.k.KessigWolfrider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kindly Ancestor", 22, Rarity.COMMON, mage.cards.k.KindlyAncestor.class)); - cards.add(new SetCardInfo("Krothuss, Lord of the Deep", 246, Rarity.RARE, mage.cards.k.KrothussLordOfTheDeep.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krothuss, Lord of the Deep", 316, Rarity.RARE, mage.cards.k.KrothussLordOfTheDeep.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krothuss, Lord of the Deep", 327, Rarity.RARE, mage.cards.k.KrothussLordOfTheDeep.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lacerate Flesh", 166, Rarity.COMMON, mage.cards.l.LacerateFlesh.class)); cards.add(new SetCardInfo("Laid to Rest", 207, Rarity.UNCOMMON, mage.cards.l.LaidToRest.class)); cards.add(new SetCardInfo("Lambholt Raconteur", 167, Rarity.UNCOMMON, mage.cards.l.LambholtRaconteur.class)); - cards.add(new SetCardInfo("Lambholt Ravager", 167, Rarity.UNCOMMON, mage.cards.l.LambholtRavager.class)); cards.add(new SetCardInfo("Lantern Bearer", 66, Rarity.COMMON, mage.cards.l.LanternBearer.class)); cards.add(new SetCardInfo("Lantern Flare", 23, Rarity.RARE, mage.cards.l.LanternFlare.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lantern Flare", 351, Rarity.RARE, mage.cards.l.LanternFlare.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lantern of the Lost", 259, Rarity.UNCOMMON, mage.cards.l.LanternOfTheLost.class)); - cards.add(new SetCardInfo("Lanterns' Lift", 66, Rarity.COMMON, mage.cards.l.LanternsLift.class)); cards.add(new SetCardInfo("Lightning Wolf", 168, Rarity.COMMON, mage.cards.l.LightningWolf.class)); cards.add(new SetCardInfo("Lunar Rejection", 67, Rarity.UNCOMMON, mage.cards.l.LunarRejection.class)); cards.add(new SetCardInfo("Magma Pummeler", 169, Rarity.UNCOMMON, mage.cards.m.MagmaPummeler.class)); - cards.add(new SetCardInfo("Malicious Invader", 121, Rarity.UNCOMMON, mage.cards.m.MaliciousInvader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Malicious Invader", 294, Rarity.UNCOMMON, mage.cards.m.MaliciousInvader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Malicious Invader", 336, Rarity.UNCOMMON, mage.cards.m.MaliciousInvader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Manaform Hellkite", 170, Rarity.MYTHIC, mage.cards.m.ManaformHellkite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Manaform Hellkite", 380, Rarity.MYTHIC, mage.cards.m.ManaformHellkite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Markov Purifier", 241, Rarity.UNCOMMON, mage.cards.m.MarkovPurifier.class, NON_FULL_USE_VARIOUS)); @@ -340,7 +286,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Mirrorhall Mimic", 68, Rarity.RARE, mage.cards.m.MirrorhallMimic.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mischievous Catgeist", 69, Rarity.UNCOMMON, mage.cards.m.MischievousCatgeist.class)); cards.add(new SetCardInfo("Moldgraf Millipede", 209, Rarity.COMMON, mage.cards.m.MoldgrafMillipede.class)); - cards.add(new SetCardInfo("Moonlit Ambusher", 212, Rarity.UNCOMMON, mage.cards.m.MoonlitAmbusher.class)); cards.add(new SetCardInfo("Mountain", 274, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 401, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -352,7 +297,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Necroduality", 70, Rarity.MYTHIC, mage.cards.n.Necroduality.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nurturing Presence", 26, Rarity.COMMON, mage.cards.n.NurturingPresence.class)); cards.add(new SetCardInfo("Oakshade Stalker", 212, Rarity.UNCOMMON, mage.cards.o.OakshadeStalker.class)); - cards.add(new SetCardInfo("Odious Witch", 127, Rarity.COMMON, mage.cards.o.OdiousWitch.class)); cards.add(new SetCardInfo("Odric, Blood-Cursed", 243, Rarity.RARE, mage.cards.o.OdricBloodCursed.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Odric, Blood-Cursed", 314, Rarity.RARE, mage.cards.o.OdricBloodCursed.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Old Rutstein", 244, Rarity.RARE, mage.cards.o.OldRutstein.class, NON_FULL_USE_VARIOUS)); @@ -382,7 +326,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Pointed Discussion", 126, Rarity.COMMON, mage.cards.p.PointedDiscussion.class)); cards.add(new SetCardInfo("Pyre Spawn", 173, Rarity.COMMON, mage.cards.p.PyreSpawn.class)); cards.add(new SetCardInfo("Radiant Grace", 31, Rarity.UNCOMMON, mage.cards.r.RadiantGrace.class)); - cards.add(new SetCardInfo("Radiant Restraints", 31, Rarity.UNCOMMON, mage.cards.r.RadiantRestraints.class)); cards.add(new SetCardInfo("Ragged Recluse", 127, Rarity.COMMON, mage.cards.r.RaggedRecluse.class)); cards.add(new SetCardInfo("Reckless Impulse", 174, Rarity.COMMON, mage.cards.r.RecklessImpulse.class)); cards.add(new SetCardInfo("Reclusive Taxidermist", 214, Rarity.UNCOMMON, mage.cards.r.ReclusiveTaxidermist.class, NON_FULL_USE_VARIOUS)); @@ -393,9 +336,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Restless Bloodseeker", 295, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Retrieve", 215, Rarity.UNCOMMON, mage.cards.r.Retrieve.class)); - cards.add(new SetCardInfo("Revealing Eye", 101, Rarity.RARE, mage.cards.r.RevealingEye.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Revealing Eye", 367, Rarity.RARE, mage.cards.r.RevealingEye.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Riphook Raider", 203, Rarity.COMMON, mage.cards.r.RiphookRaider.class)); cards.add(new SetCardInfo("Rot-Tide Gargantua", 129, Rarity.COMMON, mage.cards.r.RotTideGargantua.class)); cards.add(new SetCardInfo("Runebound Wolf", 176, Rarity.UNCOMMON, mage.cards.r.RuneboundWolf.class)); cards.add(new SetCardInfo("Runo Stromkirk", 246, Rarity.RARE, mage.cards.r.RunoStromkirk.class, NON_FULL_USE_VARIOUS)); @@ -404,7 +344,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Rural Recruit", 216, Rarity.COMMON, mage.cards.r.RuralRecruit.class)); cards.add(new SetCardInfo("Sanctify", 33, Rarity.COMMON, mage.cards.s.Sanctify.class)); cards.add(new SetCardInfo("Sanguine Statuette", 177, Rarity.UNCOMMON, mage.cards.s.SanguineStatuette.class)); - cards.add(new SetCardInfo("Savage Packmate", 234, Rarity.UNCOMMON, mage.cards.s.SavagePackmate.class)); cards.add(new SetCardInfo("Savior of Ollenbock", 330, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Savior of Ollenbock", 34, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Savior of Ollenbock", 352, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class, NON_FULL_USE_VARIOUS)); @@ -421,8 +360,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Sigarda's Summons", 36, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sigarda's Summons", 404, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sigardian Paladin", 247, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 12, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sinner's Judgment", 348, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skulking Killer", 130, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skulking Killer", 296, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skull Skaab", 248, Rarity.UNCOMMON, mage.cards.s.SkullSkaab.class)); @@ -433,7 +370,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Sorin the Mirthless", 297, Rarity.MYTHIC, mage.cards.s.SorinTheMirthless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sorin the Mirthless", 337, Rarity.MYTHIC, mage.cards.s.SorinTheMirthless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soulcipher Board", 79, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class)); - cards.add(new SetCardInfo("Spectral Binding", 48, Rarity.COMMON, mage.cards.s.SpectralBinding.class)); cards.add(new SetCardInfo("Spiked Ripsaw", 220, Rarity.UNCOMMON, mage.cards.s.SpikedRipsaw.class)); cards.add(new SetCardInfo("Splendid Reclamation", 221, Rarity.RARE, mage.cards.s.SplendidReclamation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Splendid Reclamation", 393, Rarity.RARE, mage.cards.s.SplendidReclamation.class, NON_FULL_USE_VARIOUS)); @@ -469,9 +405,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Toxrill, the Corrosive", 321, Rarity.MYTHIC, mage.cards.t.ToxrillTheCorrosive.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Traveling Minister", 39, Rarity.COMMON, mage.cards.t.TravelingMinister.class)); cards.add(new SetCardInfo("Twinblade Geist", 40, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class)); - cards.add(new SetCardInfo("Twinblade Invocation", 40, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class)); - cards.add(new SetCardInfo("Ulvenwald Behemoth", 225, Rarity.RARE, mage.cards.u.UlvenwaldBehemoth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ulvenwald Behemoth", 394, Rarity.RARE, mage.cards.u.UlvenwaldBehemoth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ulvenwald Oddity", 225, Rarity.RARE, mage.cards.u.UlvenwaldOddity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ulvenwald Oddity", 394, Rarity.RARE, mage.cards.u.UlvenwaldOddity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Undead Butler", 133, Rarity.UNCOMMON, mage.cards.u.UndeadButler.class)); @@ -497,7 +430,6 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Voldaren Estate", 267, Rarity.RARE, mage.cards.v.VoldarenEstate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Voldaren Estate", 397, Rarity.RARE, mage.cards.v.VoldarenEstate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Voldaren Estate", 403, Rarity.RARE, mage.cards.v.VoldarenEstate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Volt-Charged Berserker", 183, Rarity.UNCOMMON, mage.cards.v.VoltChargedBerserker.class)); cards.add(new SetCardInfo("Voltaic Visionary", 183, Rarity.UNCOMMON, mage.cards.v.VoltaicVisionary.class)); cards.add(new SetCardInfo("Wandering Mind", 251, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class)); cards.add(new SetCardInfo("Wanderlight Spirit", 86, Rarity.COMMON, mage.cards.w.WanderlightSpirit.class)); @@ -506,24 +438,18 @@ public final class InnistradCrimsonVow extends ExpansionSet { cards.add(new SetCardInfo("Weaver of Blossoms", 226, Rarity.COMMON, mage.cards.w.WeaverOfBlossoms.class)); cards.add(new SetCardInfo("Wedding Announcement", 355, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wedding Announcement", 45, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wedding Crasher", 229, Rarity.UNCOMMON, mage.cards.w.WeddingCrasher.class)); - cards.add(new SetCardInfo("Wedding Festivity", 355, Rarity.RARE, mage.cards.w.WeddingFestivity.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wedding Festivity", 45, Rarity.RARE, mage.cards.w.WeddingFestivity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wedding Invitation", 260, Rarity.COMMON, mage.cards.w.WeddingInvitation.class)); cards.add(new SetCardInfo("Wedding Security", 138, Rarity.UNCOMMON, mage.cards.w.WeddingSecurity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wedding Security", 299, Rarity.UNCOMMON, mage.cards.w.WeddingSecurity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Welcoming Vampire", 287, Rarity.RARE, mage.cards.w.WelcomingVampire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Welcoming Vampire", 46, Rarity.RARE, mage.cards.w.WelcomingVampire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Whispering Wizard", 88, Rarity.UNCOMMON, mage.cards.w.WhisperingWizard.class)); - cards.add(new SetCardInfo("Wildsong Howler", 205, Rarity.RARE, mage.cards.w.WildsongHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wildsong Howler", 392, Rarity.RARE, mage.cards.w.WildsongHowler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Winged Portent", 365, Rarity.RARE, mage.cards.w.WingedPortent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Winged Portent", 89, Rarity.RARE, mage.cards.w.WingedPortent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Witch's Web", 227, Rarity.COMMON, mage.cards.w.WitchsWeb.class)); cards.add(new SetCardInfo("Witness the Future", 90, Rarity.UNCOMMON, mage.cards.w.WitnessTheFuture.class)); cards.add(new SetCardInfo("Wolf Strike", 228, Rarity.COMMON, mage.cards.w.WolfStrike.class)); cards.add(new SetCardInfo("Wolfkin Outcast", 229, Rarity.UNCOMMON, mage.cards.w.WolfkinOutcast.class)); - cards.add(new SetCardInfo("Wrathful Jailbreaker", 184, Rarity.COMMON, mage.cards.w.WrathfulJailbreaker.class)); cards.add(new SetCardInfo("Wretched Throng", 91, Rarity.COMMON, mage.cards.w.WretchedThrong.class)); } diff --git a/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java b/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java index 5c5007cae54..3a0aa70042d 100644 --- a/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java +++ b/Mage.Sets/src/mage/sets/InnistradDoubleFeature.java @@ -35,40 +35,30 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Alchemist's Retrieval", 314, Rarity.COMMON, mage.cards.a.AlchemistsRetrieval.class)); cards.add(new SetCardInfo("Alluring Suitor", 408, Rarity.UNCOMMON, mage.cards.a.AlluringSuitor.class)); cards.add(new SetCardInfo("Ambitious Farmhand", 2, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class)); - cards.add(new SetCardInfo("Ancestor's Embrace", 289, Rarity.COMMON, mage.cards.a.AncestorsEmbrace.class)); cards.add(new SetCardInfo("Ancestral Anger", 409, Rarity.COMMON, mage.cards.a.AncestralAnger.class)); cards.add(new SetCardInfo("Ancient Lumberknot", 497, Rarity.UNCOMMON, mage.cards.a.AncientLumberknot.class)); cards.add(new SetCardInfo("Angelfire Ignition", 209, Rarity.RARE, mage.cards.a.AngelfireIgnition.class)); - cards.add(new SetCardInfo("Angelic Enforcer", 17, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class)); cards.add(new SetCardInfo("Angelic Quartermaster", 269, Rarity.UNCOMMON, mage.cards.a.AngelicQuartermaster.class)); cards.add(new SetCardInfo("Anje, Maid of Dishonor", 498, Rarity.RARE, mage.cards.a.AnjeMaidOfDishonor.class)); cards.add(new SetCardInfo("Apprentice Sharpshooter", 452, Rarity.COMMON, mage.cards.a.ApprenticeSharpshooter.class)); cards.add(new SetCardInfo("Arcane Infusion", 210, Rarity.UNCOMMON, mage.cards.a.ArcaneInfusion.class)); cards.add(new SetCardInfo("Archghoul of Thraben", 360, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class)); - cards.add(new SetCardInfo("Archive Haunt", 68, Rarity.UNCOMMON, mage.cards.a.ArchiveHaunt.class)); cards.add(new SetCardInfo("Ardent Elementalist", 128, Rarity.COMMON, mage.cards.a.ArdentElementalist.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 211, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 211, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class)); cards.add(new SetCardInfo("Arm the Cathars", 270, Rarity.UNCOMMON, mage.cards.a.ArmTheCathars.class)); cards.add(new SetCardInfo("Arrogant Outlaw", 84, Rarity.COMMON, mage.cards.a.ArrogantOutlaw.class)); cards.add(new SetCardInfo("Ascendant Packleader", 453, Rarity.RARE, mage.cards.a.AscendantPackleader.class)); - cards.add(new SetCardInfo("Ashmouth Dragon", 159, Rarity.RARE, mage.cards.a.AshmouthDragon.class)); cards.add(new SetCardInfo("Augur of Autumn", 168, Rarity.RARE, mage.cards.a.AugurOfAutumn.class)); cards.add(new SetCardInfo("Avabruck Caretaker", 454, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class)); - cards.add(new SetCardInfo("Awoken Demon", 100, Rarity.COMMON, mage.cards.a.AwokenDemon.class)); cards.add(new SetCardInfo("Baithook Angler", 42, Rarity.COMMON, mage.cards.b.BaithookAngler.class)); cards.add(new SetCardInfo("Ballista Watcher", 410, Rarity.UNCOMMON, mage.cards.b.BallistaWatcher.class)); - cards.add(new SetCardInfo("Ballista Wielder", 410, Rarity.UNCOMMON, mage.cards.b.BallistaWielder.class)); cards.add(new SetCardInfo("Baneblade Scoundrel", 85, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class)); - cards.add(new SetCardInfo("Baneclaw Marauder", 85, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class)); cards.add(new SetCardInfo("Bat Whisperer", 86, Rarity.COMMON, mage.cards.b.BatWhisperer.class)); cards.add(new SetCardInfo("Belligerent Guest", 411, Rarity.COMMON, mage.cards.b.BelligerentGuest.class)); cards.add(new SetCardInfo("Beloved Beggar", 3, Rarity.UNCOMMON, mage.cards.b.BelovedBeggar.class)); - cards.add(new SetCardInfo("Benevolent Geist", 61, Rarity.RARE, mage.cards.b.BenevolentGeist.class)); cards.add(new SetCardInfo("Bereaved Survivor", 4, Rarity.UNCOMMON, mage.cards.b.BereavedSurvivor.class)); cards.add(new SetCardInfo("Binding Geist", 315, Rarity.COMMON, mage.cards.b.BindingGeist.class)); cards.add(new SetCardInfo("Biolume Egg", 316, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class)); - cards.add(new SetCardInfo("Biolume Serpent", 316, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class)); cards.add(new SetCardInfo("Bird Admirer", 169, Rarity.COMMON, mage.cards.b.BirdAdmirer.class)); cards.add(new SetCardInfo("Bladebrand", 87, Rarity.COMMON, mage.cards.b.Bladebrand.class)); cards.add(new SetCardInfo("Bladestitched Skaab", 212, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class)); @@ -79,18 +69,14 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Blood Pact", 88, Rarity.COMMON, mage.cards.b.BloodPact.class)); cards.add(new SetCardInfo("Blood Petal Celebrant", 413, Rarity.COMMON, mage.cards.b.BloodPetalCelebrant.class)); cards.add(new SetCardInfo("Blood Servitor", 519, Rarity.COMMON, mage.cards.b.BloodServitor.class)); - cards.add(new SetCardInfo("Bloodbat Summoner", 404, Rarity.RARE, mage.cards.b.BloodbatSummoner.class)); cards.add(new SetCardInfo("Bloodcrazed Socialite", 363, Rarity.COMMON, mage.cards.b.BloodcrazedSocialite.class)); cards.add(new SetCardInfo("Bloodline Culling", 89, Rarity.RARE, mage.cards.b.BloodlineCulling.class)); - cards.add(new SetCardInfo("Bloodsoaked Reveler", 395, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class)); - cards.add(new SetCardInfo("Bloodsworn Knight", 364, Rarity.UNCOMMON, mage.cards.b.BloodswornKnight.class)); cards.add(new SetCardInfo("Bloodsworn Squire", 364, Rarity.UNCOMMON, mage.cards.b.BloodswornSquire.class)); cards.add(new SetCardInfo("Bloodthirsty Adversary", 129, Rarity.MYTHIC, mage.cards.b.BloodthirstyAdversary.class)); cards.add(new SetCardInfo("Bloodtithe Collector", 90, Rarity.UNCOMMON, mage.cards.b.BloodtitheCollector.class)); cards.add(new SetCardInfo("Bloodtithe Harvester", 499, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class)); cards.add(new SetCardInfo("Bloodvial Purveyor", 365, Rarity.RARE, mage.cards.b.BloodvialPurveyor.class)); cards.add(new SetCardInfo("Bloody Betrayal", 414, Rarity.COMMON, mage.cards.b.BloodyBetrayal.class)); - cards.add(new SetCardInfo("Blossom-Clad Werewolf", 493, Rarity.COMMON, mage.cards.b.BlossomCladWerewolf.class)); cards.add(new SetCardInfo("Boarded Window", 520, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class)); cards.add(new SetCardInfo("Borrowed Time", 6, Rarity.UNCOMMON, mage.cards.b.BorrowedTime.class)); cards.add(new SetCardInfo("Bounding Wolf", 170, Rarity.COMMON, mage.cards.b.BoundingWolf.class)); @@ -101,25 +87,21 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Bride's Gown", 271, Rarity.UNCOMMON, mage.cards.b.BridesGown.class)); cards.add(new SetCardInfo("Brimstone Vandal", 130, Rarity.COMMON, mage.cards.b.BrimstoneVandal.class)); cards.add(new SetCardInfo("Brine Comber", 500, Rarity.UNCOMMON, mage.cards.b.BrineComber.class)); - cards.add(new SetCardInfo("Brinebound Gift", 500, Rarity.UNCOMMON, mage.cards.b.BrineboundGift.class)); cards.add(new SetCardInfo("Brood Weaver", 173, Rarity.UNCOMMON, mage.cards.b.BroodWeaver.class)); cards.add(new SetCardInfo("Brutal Cathar", 7, Rarity.RARE, mage.cards.b.BrutalCathar.class)); cards.add(new SetCardInfo("Burly Breaker", 174, Rarity.UNCOMMON, mage.cards.b.BurlyBreaker.class)); cards.add(new SetCardInfo("Burn Down the House", 131, Rarity.RARE, mage.cards.b.BurnDownTheHouse.class)); cards.add(new SetCardInfo("Burn the Accursed", 132, Rarity.COMMON, mage.cards.b.BurnTheAccursed.class)); cards.add(new SetCardInfo("By Invitation Only", 272, Rarity.RARE, mage.cards.b.ByInvitationOnly.class)); - cards.add(new SetCardInfo("Cackling Culprit", 295, Rarity.UNCOMMON, mage.cards.c.CacklingCulprit.class)); cards.add(new SetCardInfo("Can't Stay Away", 213, Rarity.RARE, mage.cards.c.CantStayAway.class)); cards.add(new SetCardInfo("Candlegrove Witch", 8, Rarity.COMMON, mage.cards.c.CandlegroveWitch.class)); cards.add(new SetCardInfo("Candlelit Cavalry", 175, Rarity.COMMON, mage.cards.c.CandlelitCavalry.class)); cards.add(new SetCardInfo("Candletrap", 9, Rarity.COMMON, mage.cards.c.Candletrap.class)); cards.add(new SetCardInfo("Cartographer's Survey", 457, Rarity.UNCOMMON, mage.cards.c.CartographersSurvey.class)); - cards.add(new SetCardInfo("Catapult Captain", 366, Rarity.UNCOMMON, mage.cards.c.CatapultCaptain.class)); cards.add(new SetCardInfo("Catapult Fodder", 366, Rarity.UNCOMMON, mage.cards.c.CatapultFodder.class)); cards.add(new SetCardInfo("Cathar Commando", 10, Rarity.COMMON, mage.cards.c.CatharCommando.class)); cards.add(new SetCardInfo("Cathar's Call", 11, Rarity.UNCOMMON, mage.cards.c.CatharsCall.class)); cards.add(new SetCardInfo("Cathartic Pyre", 133, Rarity.UNCOMMON, mage.cards.c.CatharticPyre.class)); - cards.add(new SetCardInfo("Catlike Curiosity", 336, Rarity.UNCOMMON, mage.cards.c.CatlikeCuriosity.class)); cards.add(new SetCardInfo("Celestus Sanctifier", 12, Rarity.COMMON, mage.cards.c.CelestusSanctifier.class)); cards.add(new SetCardInfo("Cemetery Desecrator", 367, Rarity.MYTHIC, mage.cards.c.CemeteryDesecrator.class)); cards.add(new SetCardInfo("Cemetery Gatekeeper", 415, Rarity.MYTHIC, mage.cards.c.CemeteryGatekeeper.class)); @@ -130,16 +112,12 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Champion of the Perished", 91, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class)); cards.add(new SetCardInfo("Chandra, Dressed to Kill", 416, Rarity.MYTHIC, mage.cards.c.ChandraDressedToKill.class)); cards.add(new SetCardInfo("Change of Fortune", 417, Rarity.RARE, mage.cards.c.ChangeOfFortune.class)); - cards.add(new SetCardInfo("Chapel Shieldgeist", 13, Rarity.UNCOMMON, mage.cards.c.ChapelShieldgeist.class)); cards.add(new SetCardInfo("Chaplain of Alms", 13, Rarity.UNCOMMON, mage.cards.c.ChaplainOfAlms.class)); cards.add(new SetCardInfo("Child of the Pack", 501, Rarity.UNCOMMON, mage.cards.c.ChildOfThePack.class)); cards.add(new SetCardInfo("Chill of the Grave", 318, Rarity.COMMON, mage.cards.c.ChillOfTheGrave.class)); - cards.add(new SetCardInfo("Chilling Chronicle", 63, Rarity.UNCOMMON, mage.cards.c.ChillingChronicle.class)); - cards.add(new SetCardInfo("Cipherbound Spirit", 346, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class)); cards.add(new SetCardInfo("Circle of Confinement", 274, Rarity.UNCOMMON, mage.cards.c.CircleOfConfinement.class)); cards.add(new SetCardInfo("Clarion Cathars", 14, Rarity.COMMON, mage.cards.c.ClarionCathars.class)); cards.add(new SetCardInfo("Clear Shot", 176, Rarity.UNCOMMON, mage.cards.c.ClearShot.class)); - cards.add(new SetCardInfo("Clever Distraction", 276, Rarity.UNCOMMON, mage.cards.c.CleverDistraction.class)); cards.add(new SetCardInfo("Cloaked Cadet", 459, Rarity.UNCOMMON, mage.cards.c.CloakedCadet.class)); cards.add(new SetCardInfo("Cobbled Lancer", 319, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class)); cards.add(new SetCardInfo("Component Collector", 43, Rarity.COMMON, mage.cards.c.ComponentCollector.class)); @@ -152,11 +130,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Courier Bat", 369, Rarity.COMMON, mage.cards.c.CourierBat.class)); cards.add(new SetCardInfo("Covert Cutpurse", 92, Rarity.UNCOMMON, mage.cards.c.CovertCutpurse.class)); cards.add(new SetCardInfo("Covetous Castaway", 45, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class)); - cards.add(new SetCardInfo("Covetous Geist", 92, Rarity.UNCOMMON, mage.cards.c.CovetousGeist.class)); cards.add(new SetCardInfo("Cradle of Safety", 321, Rarity.COMMON, mage.cards.c.CradleOfSafety.class)); cards.add(new SetCardInfo("Crawl from the Cellar", 93, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class)); cards.add(new SetCardInfo("Crawling Infestation", 460, Rarity.UNCOMMON, mage.cards.c.CrawlingInfestation.class)); - cards.add(new SetCardInfo("Creeping Inn", 264, Rarity.MYTHIC, mage.cards.c.CreepingInn.class)); cards.add(new SetCardInfo("Creepy Puppeteer", 418, Rarity.RARE, mage.cards.c.CreepyPuppeteer.class)); cards.add(new SetCardInfo("Croaking Counterpart", 215, Rarity.RARE, mage.cards.c.CroakingCounterpart.class)); cards.add(new SetCardInfo("Crossroads Candleguide", 253, Rarity.COMMON, mage.cards.c.CrossroadsCandleguide.class)); @@ -168,33 +144,24 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Curse of Shaken Faith", 134, Rarity.RARE, mage.cards.c.CurseOfShakenFaith.class)); cards.add(new SetCardInfo("Curse of Silence", 15, Rarity.RARE, mage.cards.c.CurseOfSilence.class)); cards.add(new SetCardInfo("Curse of Surveillance", 46, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class)); - cards.add(new SetCardInfo("Dauntless Avenger", 4, Rarity.UNCOMMON, mage.cards.d.DauntlessAvenger.class)); cards.add(new SetCardInfo("Dawnhart Disciple", 463, Rarity.COMMON, mage.cards.d.DawnhartDisciple.class)); cards.add(new SetCardInfo("Dawnhart Geist", 275, Rarity.UNCOMMON, mage.cards.d.DawnhartGeist.class)); cards.add(new SetCardInfo("Dawnhart Mentor", 179, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 180, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class)); cards.add(new SetCardInfo("Dawnhart Wardens", 216, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class)); cards.add(new SetCardInfo("Daybreak Combatants", 420, Rarity.COMMON, mage.cards.d.DaybreakCombatants.class)); - cards.add(new SetCardInfo("Deadly Dancer", 408, Rarity.UNCOMMON, mage.cards.d.DeadlyDancer.class)); - cards.add(new SetCardInfo("Deathbonnet Hulk", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetHulk.class)); cards.add(new SetCardInfo("Deathbonnet Sprout", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetSprout.class)); cards.add(new SetCardInfo("Deathcap Glade", 528, Rarity.RARE, mage.cards.d.DeathcapGlade.class)); cards.add(new SetCardInfo("Defend the Celestus", 182, Rarity.UNCOMMON, mage.cards.d.DefendTheCelestus.class)); cards.add(new SetCardInfo("Defenestrate", 95, Rarity.COMMON, mage.cards.d.Defenestrate.class)); cards.add(new SetCardInfo("Delver of Secrets", 47, Rarity.UNCOMMON, mage.cards.d.DelverOfSecrets.class)); cards.add(new SetCardInfo("Demonic Bargain", 370, Rarity.RARE, mage.cards.d.DemonicBargain.class)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 217, Rarity.RARE, mage.cards.d.DennickPiousApparition.class)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 217, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class)); - cards.add(new SetCardInfo("Departed Soulkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DepartedSoulkeeper.class)); - cards.add(new SetCardInfo("Depraved Harvester", 371, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Deserted Beach", 260, Rarity.RARE, mage.cards.d.DesertedBeach.class)); cards.add(new SetCardInfo("Desperate Farmer", 371, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); cards.add(new SetCardInfo("Devious Cover-Up", 48, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); cards.add(new SetCardInfo("Devoted Grafkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DevotedGrafkeeper.class)); cards.add(new SetCardInfo("Dig Up", 464, Rarity.RARE, mage.cards.d.DigUp.class)); - cards.add(new SetCardInfo("Dire-Strain Anarchist", 448, Rarity.MYTHIC, mage.cards.d.DireStrainAnarchist.class)); - cards.add(new SetCardInfo("Dire-Strain Brawler", 203, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 174, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class)); cards.add(new SetCardInfo("Dire-Strain Rampage", 219, Rarity.RARE, mage.cards.d.DireStrainRampage.class)); cards.add(new SetCardInfo("Diregraf Horde", 96, Rarity.COMMON, mage.cards.d.DiregrafHorde.class)); cards.add(new SetCardInfo("Diregraf Rebirth", 220, Rarity.UNCOMMON, mage.cards.d.DiregrafRebirth.class)); @@ -206,7 +173,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Dominating Vampire", 421, Rarity.RARE, mage.cards.d.DominatingVampire.class)); cards.add(new SetCardInfo("Doomed Dissenter", 373, Rarity.COMMON, mage.cards.d.DoomedDissenter.class)); cards.add(new SetCardInfo("Dormant Grove", 465, Rarity.UNCOMMON, mage.cards.d.DormantGrove.class)); - cards.add(new SetCardInfo("Dorothea's Retribution", 502, Rarity.RARE, mage.cards.d.DorotheasRetribution.class)); cards.add(new SetCardInfo("Dorothea, Vengeful Victim", 502, Rarity.RARE, mage.cards.d.DorotheaVengefulVictim.class)); cards.add(new SetCardInfo("Dread Fugue", 374, Rarity.UNCOMMON, mage.cards.d.DreadFugue.class)); cards.add(new SetCardInfo("Dreadfeast Demon", 375, Rarity.RARE, mage.cards.d.DreadfeastDemon.class)); @@ -214,7 +180,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Dreadlight Monstrosity", 324, Rarity.COMMON, mage.cards.d.DreadlightMonstrosity.class)); cards.add(new SetCardInfo("Dreamroot Cascade", 529, Rarity.RARE, mage.cards.d.DreamrootCascade.class)); cards.add(new SetCardInfo("Dreamshackle Geist", 325, Rarity.RARE, mage.cards.d.DreamshackleGeist.class)); - cards.add(new SetCardInfo("Drogskol Armaments", 277, Rarity.COMMON, mage.cards.d.DrogskolArmaments.class)); cards.add(new SetCardInfo("Drogskol Infantry", 277, Rarity.COMMON, mage.cards.d.DrogskolInfantry.class)); cards.add(new SetCardInfo("Drownyard Amalgam", 50, Rarity.COMMON, mage.cards.d.DrownyardAmalgam.class)); cards.add(new SetCardInfo("Dryad's Revival", 183, Rarity.UNCOMMON, mage.cards.d.DryadsRevival.class)); @@ -225,11 +190,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Eaten Alive", 99, Rarity.COMMON, mage.cards.e.EatenAlive.class)); cards.add(new SetCardInfo("Eccentric Farmer", 185, Rarity.COMMON, mage.cards.e.EccentricFarmer.class)); cards.add(new SetCardInfo("Ecstatic Awakener", 100, Rarity.COMMON, mage.cards.e.EcstaticAwakener.class)); - cards.add(new SetCardInfo("Edgar Markov's Coffin", 503, Rarity.RARE, mage.cards.e.EdgarMarkovsCoffin.class)); cards.add(new SetCardInfo("Edgar's Awakening", 377, Rarity.UNCOMMON, mage.cards.e.EdgarsAwakening.class)); cards.add(new SetCardInfo("Edgar, Charmed Groom", 503, Rarity.RARE, mage.cards.e.EdgarCharmedGroom.class)); cards.add(new SetCardInfo("Electric Revelation", 135, Rarity.COMMON, mage.cards.e.ElectricRevelation.class)); - cards.add(new SetCardInfo("Embodiment of Flame", 141, Rarity.UNCOMMON, mage.cards.e.EmbodimentOfFlame.class)); cards.add(new SetCardInfo("End the Festivities", 422, Rarity.COMMON, mage.cards.e.EndTheFestivities.class)); cards.add(new SetCardInfo("Endless Ranks of the Dead", 535, Rarity.RARE, mage.cards.e.EndlessRanksOfTheDead.class)); cards.add(new SetCardInfo("Enduring Angel", 17, Rarity.MYTHIC, mage.cards.e.EnduringAngel.class)); @@ -247,11 +210,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Falkenrath Pit Fighter", 137, Rarity.RARE, mage.cards.f.FalkenrathPitFighter.class)); cards.add(new SetCardInfo("Famished Foragers", 138, Rarity.COMMON, mage.cards.f.FamishedForagers.class)); cards.add(new SetCardInfo("Fangblade Brigand", 139, Rarity.UNCOMMON, mage.cards.f.FangbladeBrigand.class)); - cards.add(new SetCardInfo("Fangblade Eviscerator", 139, Rarity.UNCOMMON, mage.cards.f.FangbladeEviscerator.class)); cards.add(new SetCardInfo("Fateful Absence", 18, Rarity.RARE, mage.cards.f.FatefulAbsence.class)); cards.add(new SetCardInfo("Fear of Death", 326, Rarity.COMMON, mage.cards.f.FearOfDeath.class)); cards.add(new SetCardInfo("Fearful Villager", 424, Rarity.COMMON, mage.cards.f.FearfulVillager.class)); - cards.add(new SetCardInfo("Fearsome Werewolf", 424, Rarity.COMMON, mage.cards.f.FearsomeWerewolf.class)); cards.add(new SetCardInfo("Fell Stinger", 379, Rarity.UNCOMMON, mage.cards.f.FellStinger.class)); cards.add(new SetCardInfo("Festival Crasher", 140, Rarity.COMMON, mage.cards.f.FestivalCrasher.class)); cards.add(new SetCardInfo("Field of Ruin", 262, Rarity.UNCOMMON, mage.cards.f.FieldOfRuin.class)); @@ -269,7 +230,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Forsaken Thresher", 523, Rarity.UNCOMMON, mage.cards.f.ForsakenThresher.class)); cards.add(new SetCardInfo("Foul Play", 101, Rarity.UNCOMMON, mage.cards.f.FoulPlay.class)); cards.add(new SetCardInfo("Frenzied Devils", 426, Rarity.UNCOMMON, mage.cards.f.FrenziedDevils.class)); - cards.add(new SetCardInfo("Frenzied Trapbreaker", 190, Rarity.UNCOMMON, mage.cards.f.FrenziedTrapbreaker.class)); cards.add(new SetCardInfo("Galedrifter", 55, Rarity.COMMON, mage.cards.g.Galedrifter.class)); cards.add(new SetCardInfo("Galvanic Iteration", 224, Rarity.RARE, mage.cards.g.GalvanicIteration.class)); cards.add(new SetCardInfo("Gavony Dawnguard", 20, Rarity.UNCOMMON, mage.cards.g.GavonyDawnguard.class)); @@ -278,20 +238,15 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Geistflame Reservoir", 142, Rarity.RARE, mage.cards.g.GeistflameReservoir.class)); cards.add(new SetCardInfo("Geistlight Snare", 327, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class)); cards.add(new SetCardInfo("Geistwave", 56, Rarity.COMMON, mage.cards.g.Geistwave.class)); - cards.add(new SetCardInfo("Generous Soul", 3, Rarity.UNCOMMON, mage.cards.g.GenerousSoul.class)); cards.add(new SetCardInfo("Geralf, Visionary Stitcher", 328, Rarity.RARE, mage.cards.g.GeralfVisionaryStitcher.class)); - cards.add(new SetCardInfo("Ghastly Mimicry", 335, Rarity.RARE, mage.cards.g.GhastlyMimicry.class)); - cards.add(new SetCardInfo("Ghostly Castigator", 45, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 225, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class)); cards.add(new SetCardInfo("Ghoulish Procession", 102, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class)); cards.add(new SetCardInfo("Gift of Fangs", 380, Rarity.COMMON, mage.cards.g.GiftOfFangs.class)); cards.add(new SetCardInfo("Gisa, Glorious Resurrector", 103, Rarity.RARE, mage.cards.g.GisaGloriousResurrector.class)); cards.add(new SetCardInfo("Glorious Sunrise", 467, Rarity.RARE, mage.cards.g.GloriousSunrise.class)); cards.add(new SetCardInfo("Gluttonous Guest", 381, Rarity.COMMON, mage.cards.g.GluttonousGuest.class)); - cards.add(new SetCardInfo("Gnarled Grovestrider", 465, Rarity.UNCOMMON, mage.cards.g.GnarledGrovestrider.class)); cards.add(new SetCardInfo("Graf Reaver", 382, Rarity.RARE, mage.cards.g.GrafReaver.class)); cards.add(new SetCardInfo("Grafted Identity", 57, Rarity.RARE, mage.cards.g.GraftedIdentity.class)); - cards.add(new SetCardInfo("Graveyard Glutton", 104, Rarity.RARE, mage.cards.g.GraveyardGlutton.class)); cards.add(new SetCardInfo("Graveyard Trespasser", 104, Rarity.RARE, mage.cards.g.GraveyardTrespasser.class)); cards.add(new SetCardInfo("Grisly Ritual", 383, Rarity.COMMON, mage.cards.g.GrislyRitual.class)); cards.add(new SetCardInfo("Grizzly Ghoul", 226, Rarity.UNCOMMON, mage.cards.g.GrizzlyGhoul.class)); @@ -299,39 +254,32 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Groom's Finery", 384, Rarity.UNCOMMON, mage.cards.g.GroomsFinery.class)); cards.add(new SetCardInfo("Gryff Rider", 282, Rarity.COMMON, mage.cards.g.GryffRider.class)); cards.add(new SetCardInfo("Gryffwing Cavalry", 283, Rarity.UNCOMMON, mage.cards.g.GryffwingCavalry.class)); - cards.add(new SetCardInfo("Gutter Shortcut", 329, Rarity.UNCOMMON, mage.cards.g.GutterShortcut.class)); cards.add(new SetCardInfo("Gutter Skulker", 329, Rarity.UNCOMMON, mage.cards.g.GutterSkulker.class)); cards.add(new SetCardInfo("Halana and Alena, Partners", 506, Rarity.RARE, mage.cards.h.HalanaAndAlenaPartners.class)); cards.add(new SetCardInfo("Hallowed Haunting", 284, Rarity.MYTHIC, mage.cards.h.HallowedHaunting.class)); cards.add(new SetCardInfo("Hallowed Respite", 227, Rarity.RARE, mage.cards.h.HallowedRespite.class)); cards.add(new SetCardInfo("Hamlet Vanguard", 468, Rarity.RARE, mage.cards.h.HamletVanguard.class)); - cards.add(new SetCardInfo("Harvesttide Assailant", 143, Rarity.COMMON, mage.cards.h.HarvesttideAssailant.class)); cards.add(new SetCardInfo("Harvesttide Infiltrator", 143, Rarity.COMMON, mage.cards.h.HarvesttideInfiltrator.class)); cards.add(new SetCardInfo("Harvesttide Sentry", 186, Rarity.COMMON, mage.cards.h.HarvesttideSentry.class)); - cards.add(new SetCardInfo("Hauken's Insight", 332, Rarity.MYTHIC, mage.cards.h.HaukensInsight.class)); cards.add(new SetCardInfo("Haunted Ridge", 263, Rarity.RARE, mage.cards.h.HauntedRidge.class)); cards.add(new SetCardInfo("Headless Rider", 385, Rarity.RARE, mage.cards.h.HeadlessRider.class)); cards.add(new SetCardInfo("Hedgewitch's Mask", 23, Rarity.COMMON, mage.cards.h.HedgewitchsMask.class)); cards.add(new SetCardInfo("Heirloom Mirror", 105, Rarity.UNCOMMON, mage.cards.h.HeirloomMirror.class)); cards.add(new SetCardInfo("Henrika Domnathi", 386, Rarity.MYTHIC, mage.cards.h.HenrikaDomnathi.class)); - cards.add(new SetCardInfo("Henrika, Infernal Seer", 386, Rarity.MYTHIC, mage.cards.h.HenrikaInfernalSeer.class)); cards.add(new SetCardInfo("Hero's Downfall", 387, Rarity.UNCOMMON, mage.cards.h.HerosDownfall.class)); cards.add(new SetCardInfo("Heron of Hope", 285, Rarity.COMMON, mage.cards.h.HeronOfHope.class)); cards.add(new SetCardInfo("Heron-Blessed Geist", 286, Rarity.COMMON, mage.cards.h.HeronBlessedGeist.class)); cards.add(new SetCardInfo("Hiveheart Shaman", 469, Rarity.RARE, mage.cards.h.HiveheartShaman.class)); cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 454, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class)); cards.add(new SetCardInfo("Honeymoon Hearse", 427, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class)); cards.add(new SetCardInfo("Honored Heirloom", 524, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class)); - cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class)); cards.add(new SetCardInfo("Hookhand Mariner", 470, Rarity.COMMON, mage.cards.h.HookhandMariner.class)); cards.add(new SetCardInfo("Hopeful Initiate", 287, Rarity.RARE, mage.cards.h.HopefulInitiate.class)); cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class)); cards.add(new SetCardInfo("Hound Tamer", 187, Rarity.UNCOMMON, mage.cards.h.HoundTamer.class)); cards.add(new SetCardInfo("Howl of the Hunt", 188, Rarity.COMMON, mage.cards.h.HowlOfTheHunt.class)); cards.add(new SetCardInfo("Howling Moon", 471, Rarity.RARE, mage.cards.h.HowlingMoon.class)); - cards.add(new SetCardInfo("Howlpack Avenger", 429, Rarity.RARE, mage.cards.h.HowlpackAvenger.class)); cards.add(new SetCardInfo("Howlpack Piper", 472, Rarity.RARE, mage.cards.h.HowlpackPiper.class)); cards.add(new SetCardInfo("Hullbreaker Horror", 330, Rarity.RARE, mage.cards.h.HullbreakerHorror.class)); cards.add(new SetCardInfo("Hungry for More", 228, Rarity.UNCOMMON, mage.cards.h.HungryForMore.class)); @@ -340,10 +288,7 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Immolation", 144, Rarity.COMMON, mage.cards.i.Immolation.class)); cards.add(new SetCardInfo("Infernal Grasp", 107, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class)); cards.add(new SetCardInfo("Infestation Expert", 473, Rarity.UNCOMMON, mage.cards.i.InfestationExpert.class)); - cards.add(new SetCardInfo("Infested Werewolf", 473, Rarity.UNCOMMON, mage.cards.i.InfestedWerewolf.class)); - cards.add(new SetCardInfo("Inherited Fiend", 105, Rarity.UNCOMMON, mage.cards.i.InheritedFiend.class)); cards.add(new SetCardInfo("Innocent Traveler", 388, Rarity.UNCOMMON, mage.cards.i.InnocentTraveler.class)); - cards.add(new SetCardInfo("Insectile Aberration", 47, Rarity.UNCOMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Inspired Idea", 331, Rarity.RARE, mage.cards.i.InspiredIdea.class)); cards.add(new SetCardInfo("Into the Night", 430, Rarity.UNCOMMON, mage.cards.i.IntoTheNight.class)); cards.add(new SetCardInfo("Intrepid Adversary", 25, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class)); @@ -353,7 +298,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Jadar, Ghoulcaller of Nephalia", 108, Rarity.RARE, mage.cards.j.JadarGhoulcallerOfNephalia.class)); cards.add(new SetCardInfo("Jerren, Corrupted Bishop", 109, Rarity.MYTHIC, mage.cards.j.JerrenCorruptedBishop.class)); cards.add(new SetCardInfo("Join the Dance", 229, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class)); - cards.add(new SetCardInfo("Katilda's Rising Dawn", 288, Rarity.RARE, mage.cards.k.KatildasRisingDawn.class)); cards.add(new SetCardInfo("Katilda, Dawnhart Martyr", 288, Rarity.RARE, mage.cards.k.KatildaDawnhartMartyr.class)); cards.add(new SetCardInfo("Katilda, Dawnhart Prime", 230, Rarity.RARE, mage.cards.k.KatildaDawnhartPrime.class)); cards.add(new SetCardInfo("Kaya, Geist Hunter", 507, Rarity.MYTHIC, mage.cards.k.KayaGeistHunter.class)); @@ -361,34 +305,27 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Kessig Naturalist", 231, Rarity.UNCOMMON, mage.cards.k.KessigNaturalist.class)); cards.add(new SetCardInfo("Kessig Wolfrider", 432, Rarity.RARE, mage.cards.k.KessigWolfrider.class)); cards.add(new SetCardInfo("Kindly Ancestor", 289, Rarity.COMMON, mage.cards.k.KindlyAncestor.class)); - cards.add(new SetCardInfo("Krothuss, Lord of the Deep", 513, Rarity.RARE, mage.cards.k.KrothussLordOfTheDeep.class)); cards.add(new SetCardInfo("Lacerate Flesh", 433, Rarity.COMMON, mage.cards.l.LacerateFlesh.class)); cards.add(new SetCardInfo("Laid to Rest", 474, Rarity.UNCOMMON, mage.cards.l.LaidToRest.class)); cards.add(new SetCardInfo("Lambholt Harrier", 145, Rarity.COMMON, mage.cards.l.LambholtHarrier.class)); cards.add(new SetCardInfo("Lambholt Raconteur", 434, Rarity.UNCOMMON, mage.cards.l.LambholtRaconteur.class)); - cards.add(new SetCardInfo("Lambholt Ravager", 434, Rarity.UNCOMMON, mage.cards.l.LambholtRavager.class)); cards.add(new SetCardInfo("Lantern Bearer", 333, Rarity.COMMON, mage.cards.l.LanternBearer.class)); cards.add(new SetCardInfo("Lantern Flare", 290, Rarity.RARE, mage.cards.l.LanternFlare.class)); cards.add(new SetCardInfo("Lantern of the Lost", 526, Rarity.UNCOMMON, mage.cards.l.LanternOfTheLost.class)); - cards.add(new SetCardInfo("Lanterns' Lift", 333, Rarity.COMMON, mage.cards.l.LanternsLift.class)); cards.add(new SetCardInfo("Larder Zombie", 58, Rarity.COMMON, mage.cards.l.LarderZombie.class)); - cards.add(new SetCardInfo("Leeching Lurker", 94, Rarity.RARE, mage.cards.l.LeechingLurker.class)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 59, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 232, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class)); cards.add(new SetCardInfo("Light Up the Night", 146, Rarity.RARE, mage.cards.l.LightUpTheNight.class)); cards.add(new SetCardInfo("Lightning Wolf", 435, Rarity.COMMON, mage.cards.l.LightningWolf.class)); cards.add(new SetCardInfo("Locked in the Cemetery", 60, Rarity.COMMON, mage.cards.l.LockedInTheCemetery.class)); cards.add(new SetCardInfo("Lord of the Forsaken", 110, Rarity.MYTHIC, mage.cards.l.LordOfTheForsaken.class)); - cards.add(new SetCardInfo("Lord of the Ulvenwald", 231, Rarity.UNCOMMON, mage.cards.l.LordOfTheUlvenwald.class)); cards.add(new SetCardInfo("Loyal Gryff", 26, Rarity.UNCOMMON, mage.cards.l.LoyalGryff.class)); cards.add(new SetCardInfo("Ludevic, Necrogenius", 233, Rarity.RARE, mage.cards.l.LudevicNecrogenius.class)); - cards.add(new SetCardInfo("Luminous Phantom", 27, Rarity.COMMON, mage.cards.l.LuminousPhantom.class)); cards.add(new SetCardInfo("Lunar Frenzy", 147, Rarity.UNCOMMON, mage.cards.l.LunarFrenzy.class)); cards.add(new SetCardInfo("Lunar Rejection", 334, Rarity.UNCOMMON, mage.cards.l.LunarRejection.class)); cards.add(new SetCardInfo("Lunarch Veteran", 27, Rarity.COMMON, mage.cards.l.LunarchVeteran.class)); cards.add(new SetCardInfo("Magma Pummeler", 436, Rarity.UNCOMMON, mage.cards.m.MagmaPummeler.class)); cards.add(new SetCardInfo("Malevolent Hermit", 61, Rarity.RARE, mage.cards.m.MalevolentHermit.class)); - cards.add(new SetCardInfo("Malicious Invader", 388, Rarity.UNCOMMON, mage.cards.m.MaliciousInvader.class)); cards.add(new SetCardInfo("Manaform Hellkite", 437, Rarity.MYTHIC, mage.cards.m.ManaformHellkite.class)); cards.add(new SetCardInfo("Markov Purifier", 508, Rarity.UNCOMMON, mage.cards.m.MarkovPurifier.class)); cards.add(new SetCardInfo("Markov Retribution", 438, Rarity.UNCOMMON, mage.cards.m.MarkovRetribution.class)); @@ -402,19 +339,15 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Mirrorhall Mimic", 335, Rarity.RARE, mage.cards.m.MirrorhallMimic.class)); cards.add(new SetCardInfo("Mischievous Catgeist", 336, Rarity.UNCOMMON, mage.cards.m.MischievousCatgeist.class)); cards.add(new SetCardInfo("Moldgraf Millipede", 476, Rarity.COMMON, mage.cards.m.MoldgrafMillipede.class)); - cards.add(new SetCardInfo("Moonlit Ambusher", 479, Rarity.UNCOMMON, mage.cards.m.MoonlitAmbusher.class)); - cards.add(new SetCardInfo("Moonrage Brute", 7, Rarity.RARE, mage.cards.m.MoonrageBrute.class)); cards.add(new SetCardInfo("Moonrager's Slash", 148, Rarity.COMMON, mage.cards.m.MoonragersSlash.class)); cards.add(new SetCardInfo("Moonsilver Key", 255, Rarity.UNCOMMON, mage.cards.m.MoonsilverKey.class)); cards.add(new SetCardInfo("Moonveil Regent", 149, Rarity.MYTHIC, mage.cards.m.MoonveilRegent.class)); cards.add(new SetCardInfo("Morbid Opportunist", 113, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class)); cards.add(new SetCardInfo("Morkrut Behemoth", 114, Rarity.COMMON, mage.cards.m.MorkrutBehemoth.class)); - cards.add(new SetCardInfo("Morning Apparition", 28, Rarity.COMMON, mage.cards.m.MorningApparition.class)); cards.add(new SetCardInfo("Mounted Dreadknight", 150, Rarity.COMMON, mage.cards.m.MountedDreadknight.class)); cards.add(new SetCardInfo("Mourning Patrol", 28, Rarity.COMMON, mage.cards.m.MourningPatrol.class)); cards.add(new SetCardInfo("Mulch", 477, Rarity.COMMON, mage.cards.m.Mulch.class)); cards.add(new SetCardInfo("Mysterious Tome", 63, Rarity.UNCOMMON, mage.cards.m.MysteriousTome.class)); - cards.add(new SetCardInfo("Mystic Monstrosity", 256, Rarity.UNCOMMON, mage.cards.m.MysticMonstrosity.class)); cards.add(new SetCardInfo("Mystic Skull", 256, Rarity.UNCOMMON, mage.cards.m.MysticSkull.class)); cards.add(new SetCardInfo("Nature's Embrace", 478, Rarity.COMMON, mage.cards.n.NaturesEmbrace.class)); cards.add(new SetCardInfo("Nebelgast Beguiler", 292, Rarity.COMMON, mage.cards.n.NebelgastBeguiler.class)); @@ -427,10 +360,8 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Nurturing Presence", 293, Rarity.COMMON, mage.cards.n.NurturingPresence.class)); cards.add(new SetCardInfo("Oakshade Stalker", 479, Rarity.UNCOMMON, mage.cards.o.OakshadeStalker.class)); cards.add(new SetCardInfo("Obsessive Astronomer", 152, Rarity.UNCOMMON, mage.cards.o.ObsessiveAstronomer.class)); - cards.add(new SetCardInfo("Odious Witch", 394, Rarity.COMMON, mage.cards.o.OdiousWitch.class)); cards.add(new SetCardInfo("Odric's Outrider", 29, Rarity.UNCOMMON, mage.cards.o.OdricsOutrider.class)); cards.add(new SetCardInfo("Odric, Blood-Cursed", 510, Rarity.RARE, mage.cards.o.OdricBloodCursed.class)); - cards.add(new SetCardInfo("Olag, Ludevic's Hubris", 233, Rarity.RARE, mage.cards.o.OlagLudevicsHubris.class)); cards.add(new SetCardInfo("Old Rutstein", 511, Rarity.RARE, mage.cards.o.OldRutstein.class)); cards.add(new SetCardInfo("Old Stickfingers", 234, Rarity.RARE, mage.cards.o.OldStickfingers.class)); cards.add(new SetCardInfo("Olivia's Attendants", 439, Rarity.RARE, mage.cards.o.OliviasAttendants.class)); @@ -439,7 +370,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Ollenbock Escort", 294, Rarity.UNCOMMON, mage.cards.o.OllenbockEscort.class)); cards.add(new SetCardInfo("Ominous Roost", 65, Rarity.UNCOMMON, mage.cards.o.OminousRoost.class)); cards.add(new SetCardInfo("Organ Hoarder", 66, Rarity.COMMON, mage.cards.o.OrganHoarder.class)); - cards.add(new SetCardInfo("Ormendahl, the Corrupter", 109, Rarity.MYTHIC, mage.cards.o.OrmendahlTheCorrupter.class)); cards.add(new SetCardInfo("Otherworldly Gaze", 67, Rarity.COMMON, mage.cards.o.OtherworldlyGaze.class)); cards.add(new SetCardInfo("Outland Liberator", 190, Rarity.UNCOMMON, mage.cards.o.OutlandLiberator.class)); cards.add(new SetCardInfo("Overcharged Amalgam", 338, Rarity.RARE, mage.cards.o.OverchargedAmalgam.class)); @@ -462,13 +392,11 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Play with Fire", 154, Rarity.UNCOMMON, mage.cards.p.PlayWithFire.class)); cards.add(new SetCardInfo("Plummet", 193, Rarity.COMMON, mage.cards.p.Plummet.class)); cards.add(new SetCardInfo("Pointed Discussion", 393, Rarity.COMMON, mage.cards.p.PointedDiscussion.class)); - cards.add(new SetCardInfo("Poppet Factory", 71, Rarity.MYTHIC, mage.cards.p.PoppetFactory.class)); cards.add(new SetCardInfo("Poppet Stitcher", 71, Rarity.MYTHIC, mage.cards.p.PoppetStitcher.class)); cards.add(new SetCardInfo("Primal Adversary", 194, Rarity.MYTHIC, mage.cards.p.PrimalAdversary.class)); cards.add(new SetCardInfo("Purifying Dragon", 155, Rarity.UNCOMMON, mage.cards.p.PurifyingDragon.class)); cards.add(new SetCardInfo("Pyre Spawn", 440, Rarity.COMMON, mage.cards.p.PyreSpawn.class)); cards.add(new SetCardInfo("Radiant Grace", 298, Rarity.UNCOMMON, mage.cards.r.RadiantGrace.class)); - cards.add(new SetCardInfo("Radiant Restraints", 298, Rarity.UNCOMMON, mage.cards.r.RadiantRestraints.class)); cards.add(new SetCardInfo("Ragged Recluse", 394, Rarity.COMMON, mage.cards.r.RaggedRecluse.class)); cards.add(new SetCardInfo("Raze the Effigy", 156, Rarity.COMMON, mage.cards.r.RazeTheEffigy.class)); cards.add(new SetCardInfo("Reckless Impulse", 441, Rarity.COMMON, mage.cards.r.RecklessImpulse.class)); @@ -481,9 +409,7 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Restless Bloodseeker", 395, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class)); cards.add(new SetCardInfo("Retrieve", 482, Rarity.UNCOMMON, mage.cards.r.Retrieve.class)); cards.add(new SetCardInfo("Return to Nature", 195, Rarity.COMMON, mage.cards.r.ReturnToNature.class)); - cards.add(new SetCardInfo("Revealing Eye", 368, Rarity.RARE, mage.cards.r.RevealingEye.class)); cards.add(new SetCardInfo("Revenge of the Drowned", 72, Rarity.COMMON, mage.cards.r.RevengeOfTheDrowned.class)); - cards.add(new SetCardInfo("Riphook Raider", 470, Rarity.COMMON, mage.cards.r.RiphookRaider.class)); cards.add(new SetCardInfo("Rise of the Ants", 196, Rarity.UNCOMMON, mage.cards.r.RiseOfTheAnts.class)); cards.add(new SetCardInfo("Rite of Harmony", 236, Rarity.RARE, mage.cards.r.RiteOfHarmony.class)); cards.add(new SetCardInfo("Rite of Oblivion", 237, Rarity.UNCOMMON, mage.cards.r.RiteOfOblivion.class)); @@ -500,14 +426,11 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Sanctify", 300, Rarity.COMMON, mage.cards.s.Sanctify.class)); cards.add(new SetCardInfo("Sanguine Statuette", 444, Rarity.UNCOMMON, mage.cards.s.SanguineStatuette.class)); cards.add(new SetCardInfo("Saryth, the Viper's Fang", 197, Rarity.RARE, mage.cards.s.SarythTheVipersFang.class)); - cards.add(new SetCardInfo("Savage Packmate", 501, Rarity.UNCOMMON, mage.cards.s.SavagePackmate.class)); cards.add(new SetCardInfo("Savior of Ollenbock", 301, Rarity.MYTHIC, mage.cards.s.SaviorOfOllenbock.class)); cards.add(new SetCardInfo("Sawblade Slinger", 484, Rarity.UNCOMMON, mage.cards.s.SawbladeSlinger.class)); cards.add(new SetCardInfo("Scattered Thoughts", 341, Rarity.COMMON, mage.cards.s.ScatteredThoughts.class)); cards.add(new SetCardInfo("Screaming Swarm", 342, Rarity.UNCOMMON, mage.cards.s.ScreamingSwarm.class)); - cards.add(new SetCardInfo("Seafaring Werewolf", 80, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class)); cards.add(new SetCardInfo("Search Party Captain", 32, Rarity.COMMON, mage.cards.s.SearchPartyCaptain.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 2, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class)); cards.add(new SetCardInfo("Secrets of the Key", 73, Rarity.COMMON, mage.cards.s.SecretsOfTheKey.class)); cards.add(new SetCardInfo("Seize the Storm", 158, Rarity.UNCOMMON, mage.cards.s.SeizeTheStorm.class)); cards.add(new SetCardInfo("Selhoff Entomber", 343, Rarity.COMMON, mage.cards.s.SelhoffEntomber.class)); @@ -526,7 +449,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Sigardian Paladin", 514, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class)); cards.add(new SetCardInfo("Sigardian Savior", 34, Rarity.MYTHIC, mage.cards.s.SigardianSavior.class)); cards.add(new SetCardInfo("Silver Bolt", 258, Rarity.COMMON, mage.cards.s.SilverBolt.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class)); cards.add(new SetCardInfo("Siphon Insight", 241, Rarity.RARE, mage.cards.s.SiphonInsight.class)); cards.add(new SetCardInfo("Skaab Wrangler", 75, Rarity.UNCOMMON, mage.cards.s.SkaabWrangler.class)); cards.add(new SetCardInfo("Skulking Killer", 397, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class)); @@ -542,14 +464,11 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Soul-Guide Gryff", 35, Rarity.COMMON, mage.cards.s.SoulGuideGryff.class)); cards.add(new SetCardInfo("Soulcipher Board", 346, Rarity.UNCOMMON, mage.cards.s.SoulcipherBoard.class)); cards.add(new SetCardInfo("Spectral Adversary", 77, Rarity.MYTHIC, mage.cards.s.SpectralAdversary.class)); - cards.add(new SetCardInfo("Spectral Binding", 315, Rarity.COMMON, mage.cards.s.SpectralBinding.class)); - cards.add(new SetCardInfo("Spellrune Howler", 160, Rarity.UNCOMMON, mage.cards.s.SpellruneHowler.class)); cards.add(new SetCardInfo("Spellrune Painter", 160, Rarity.UNCOMMON, mage.cards.s.SpellrunePainter.class)); cards.add(new SetCardInfo("Spiked Ripsaw", 487, Rarity.UNCOMMON, mage.cards.s.SpikedRipsaw.class)); cards.add(new SetCardInfo("Splendid Reclamation", 488, Rarity.RARE, mage.cards.s.SplendidReclamation.class)); cards.add(new SetCardInfo("Spore Crawler", 489, Rarity.COMMON, mage.cards.s.SporeCrawler.class)); cards.add(new SetCardInfo("Sporeback Wolf", 490, Rarity.COMMON, mage.cards.s.SporebackWolf.class)); - cards.add(new SetCardInfo("Stalking Predator", 120, Rarity.COMMON, mage.cards.s.StalkingPredator.class)); cards.add(new SetCardInfo("Startle", 78, Rarity.COMMON, mage.cards.s.Startle.class)); cards.add(new SetCardInfo("Steelclad Spirit", 347, Rarity.COMMON, mage.cards.s.SteelcladSpirit.class)); cards.add(new SetCardInfo("Stensia Uprising", 445, Rarity.RARE, mage.cards.s.StensiaUprising.class)); @@ -557,11 +476,9 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Stolen Vitality", 161, Rarity.COMMON, mage.cards.s.StolenVitality.class)); cards.add(new SetCardInfo("Storm Skreelix", 243, Rarity.UNCOMMON, mage.cards.s.StormSkreelix.class)); cards.add(new SetCardInfo("Storm the Festival", 200, Rarity.RARE, mage.cards.s.StormTheFestival.class)); - cards.add(new SetCardInfo("Storm-Charged Slasher", 157, Rarity.RARE, mage.cards.s.StormChargedSlasher.class)); cards.add(new SetCardInfo("Stormcarved Coast", 532, Rarity.RARE, mage.cards.s.StormcarvedCoast.class)); cards.add(new SetCardInfo("Stormchaser Drake", 349, Rarity.UNCOMMON, mage.cards.s.StormchaserDrake.class)); cards.add(new SetCardInfo("Stormrider Spirit", 79, Rarity.COMMON, mage.cards.s.StormriderSpirit.class)); - cards.add(new SetCardInfo("Strangling Grasp", 126, Rarity.UNCOMMON, mage.cards.s.StranglingGrasp.class)); cards.add(new SetCardInfo("Stromkirk Bloodthief", 123, Rarity.UNCOMMON, mage.cards.s.StromkirkBloodthief.class)); cards.add(new SetCardInfo("Stuffed Bear", 259, Rarity.COMMON, mage.cards.s.StuffedBear.class)); cards.add(new SetCardInfo("Sundown Pass", 533, Rarity.RARE, mage.cards.s.SundownPass.class)); @@ -578,7 +495,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Tainted Adversary", 124, Rarity.MYTHIC, mage.cards.t.TaintedAdversary.class)); cards.add(new SetCardInfo("Tapping at the Window", 201, Rarity.COMMON, mage.cards.t.TappingAtTheWindow.class)); cards.add(new SetCardInfo("Tavern Ruffian", 163, Rarity.COMMON, mage.cards.t.TavernRuffian.class)); - cards.add(new SetCardInfo("Tavern Smasher", 163, Rarity.COMMON, mage.cards.t.TavernSmasher.class)); cards.add(new SetCardInfo("Teferi, Who Slows the Sunset", 245, Rarity.MYTHIC, mage.cards.t.TeferiWhoSlowsTheSunset.class)); cards.add(new SetCardInfo("Thalia, Guardian of Thraben", 305, Rarity.RARE, mage.cards.t.ThaliaGuardianOfThraben.class)); cards.add(new SetCardInfo("The Celestus", 252, Rarity.RARE, mage.cards.t.TheCelestus.class)); @@ -590,17 +506,13 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Tireless Hauler", 203, Rarity.COMMON, mage.cards.t.TirelessHauler.class)); cards.add(new SetCardInfo("Torens, Fist of the Angels", 516, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class)); cards.add(new SetCardInfo("Tovolar's Huntmaster", 204, Rarity.RARE, mage.cards.t.TovolarsHuntmaster.class)); - cards.add(new SetCardInfo("Tovolar's Packleader", 204, Rarity.RARE, mage.cards.t.TovolarsPackleader.class)); cards.add(new SetCardInfo("Tovolar, Dire Overlord", 246, Rarity.RARE, mage.cards.t.TovolarDireOverlord.class)); - cards.add(new SetCardInfo("Tovolar, the Midnight Scourge", 246, Rarity.RARE, mage.cards.t.TovolarTheMidnightScourge.class)); cards.add(new SetCardInfo("Toxic Scorpion", 491, Rarity.COMMON, mage.cards.t.ToxicScorpion.class)); cards.add(new SetCardInfo("Toxrill, the Corrosive", 399, Rarity.MYTHIC, mage.cards.t.ToxrillTheCorrosive.class)); cards.add(new SetCardInfo("Traveling Minister", 306, Rarity.COMMON, mage.cards.t.TravelingMinister.class)); cards.add(new SetCardInfo("Triskaidekaphile", 81, Rarity.RARE, mage.cards.t.Triskaidekaphile.class)); cards.add(new SetCardInfo("Turn the Earth", 205, Rarity.UNCOMMON, mage.cards.t.TurnTheEarth.class)); cards.add(new SetCardInfo("Twinblade Geist", 307, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class)); - cards.add(new SetCardInfo("Twinblade Invocation", 307, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class)); - cards.add(new SetCardInfo("Ulvenwald Behemoth", 492, Rarity.RARE, mage.cards.u.UlvenwaldBehemoth.class)); cards.add(new SetCardInfo("Ulvenwald Oddity", 492, Rarity.RARE, mage.cards.u.UlvenwaldOddity.class)); cards.add(new SetCardInfo("Unblinking Observer", 82, Rarity.COMMON, mage.cards.u.UnblinkingObserver.class)); cards.add(new SetCardInfo("Undead Butler", 400, Rarity.UNCOMMON, mage.cards.u.UndeadButler.class)); @@ -610,7 +522,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Unnatural Growth", 206, Rarity.RARE, mage.cards.u.UnnaturalGrowth.class)); cards.add(new SetCardInfo("Unnatural Moonrise", 247, Rarity.UNCOMMON, mage.cards.u.UnnaturalMoonrise.class)); cards.add(new SetCardInfo("Unruly Mob", 40, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); - cards.add(new SetCardInfo("Untamed Pup", 187, Rarity.UNCOMMON, mage.cards.u.UntamedPup.class)); cards.add(new SetCardInfo("Vadrik, Astral Archmage", 248, Rarity.RARE, mage.cards.v.VadrikAstralArchmage.class)); cards.add(new SetCardInfo("Valorous Stance", 309, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class)); cards.add(new SetCardInfo("Vampire Interloper", 125, Rarity.COMMON, mage.cards.v.VampireInterloper.class)); @@ -621,7 +532,6 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Vanquish the Horde", 41, Rarity.RARE, mage.cards.v.VanquishTheHorde.class)); cards.add(new SetCardInfo("Vengeful Strangler", 126, Rarity.UNCOMMON, mage.cards.v.VengefulStrangler.class)); cards.add(new SetCardInfo("Vilespawn Spider", 517, Rarity.UNCOMMON, mage.cards.v.VilespawnSpider.class)); - cards.add(new SetCardInfo("Village Reavers", 165, Rarity.UNCOMMON, mage.cards.v.VillageReavers.class)); cards.add(new SetCardInfo("Village Watch", 165, Rarity.UNCOMMON, mage.cards.v.VillageWatch.class)); cards.add(new SetCardInfo("Vivisection", 83, Rarity.UNCOMMON, mage.cards.v.Vivisection.class)); cards.add(new SetCardInfo("Voice of the Blessed", 311, Rarity.RARE, mage.cards.v.VoiceOfTheBlessed.class)); @@ -631,9 +541,7 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Voldaren Epicure", 449, Rarity.COMMON, mage.cards.v.VoldarenEpicure.class)); cards.add(new SetCardInfo("Voldaren Estate", 534, Rarity.RARE, mage.cards.v.VoldarenEstate.class)); cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class)); - cards.add(new SetCardInfo("Volt-Charged Berserker", 450, Rarity.UNCOMMON, mage.cards.v.VoltChargedBerserker.class)); cards.add(new SetCardInfo("Voltaic Visionary", 450, Rarity.UNCOMMON, mage.cards.v.VoltaicVisionary.class)); - cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class)); cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class)); cards.add(new SetCardInfo("Wandering Mind", 518, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class)); cards.add(new SetCardInfo("Wanderlight Spirit", 353, Rarity.COMMON, mage.cards.w.WanderlightSpirit.class)); @@ -641,22 +549,17 @@ public final class InnistradDoubleFeature extends ExpansionSet { cards.add(new SetCardInfo("Weary Prisoner", 451, Rarity.COMMON, mage.cards.w.WearyPrisoner.class)); cards.add(new SetCardInfo("Weaver of Blossoms", 493, Rarity.COMMON, mage.cards.w.WeaverOfBlossoms.class)); cards.add(new SetCardInfo("Wedding Announcement", 312, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class)); - cards.add(new SetCardInfo("Wedding Crasher", 496, Rarity.UNCOMMON, mage.cards.w.WeddingCrasher.class)); - cards.add(new SetCardInfo("Wedding Festivity", 312, Rarity.RARE, mage.cards.w.WeddingFestivity.class)); cards.add(new SetCardInfo("Wedding Invitation", 527, Rarity.COMMON, mage.cards.w.WeddingInvitation.class)); cards.add(new SetCardInfo("Wedding Security", 405, Rarity.UNCOMMON, mage.cards.w.WeddingSecurity.class)); cards.add(new SetCardInfo("Welcoming Vampire", 313, Rarity.RARE, mage.cards.w.WelcomingVampire.class)); cards.add(new SetCardInfo("Whispering Wizard", 355, Rarity.UNCOMMON, mage.cards.w.WhisperingWizard.class)); - cards.add(new SetCardInfo("Wildsong Howler", 472, Rarity.RARE, mage.cards.w.WildsongHowler.class)); cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class)); - cards.add(new SetCardInfo("Wing Shredder", 169, Rarity.COMMON, mage.cards.w.WingShredder.class)); cards.add(new SetCardInfo("Winged Portent", 356, Rarity.RARE, mage.cards.w.WingedPortent.class)); cards.add(new SetCardInfo("Winterthorn Blessing", 251, Rarity.UNCOMMON, mage.cards.w.WinterthornBlessing.class)); cards.add(new SetCardInfo("Witch's Web", 494, Rarity.COMMON, mage.cards.w.WitchsWeb.class)); cards.add(new SetCardInfo("Witness the Future", 357, Rarity.UNCOMMON, mage.cards.w.WitnessTheFuture.class)); cards.add(new SetCardInfo("Wolf Strike", 495, Rarity.COMMON, mage.cards.w.WolfStrike.class)); cards.add(new SetCardInfo("Wolfkin Outcast", 496, Rarity.UNCOMMON, mage.cards.w.WolfkinOutcast.class)); - cards.add(new SetCardInfo("Wrathful Jailbreaker", 451, Rarity.COMMON, mage.cards.w.WrathfulJailbreaker.class)); cards.add(new SetCardInfo("Wrenn and Seven", 208, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class)); cards.add(new SetCardInfo("Wretched Throng", 358, Rarity.COMMON, mage.cards.w.WretchedThrong.class)); } diff --git a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java index 5617a15cdf1..7bfffd9308b 100644 --- a/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java +++ b/Mage.Sets/src/mage/sets/InnistradMidnightHunt.java @@ -45,32 +45,19 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Ambitious Farmhand", 2, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class)); cards.add(new SetCardInfo("Angelfire Ignition", 209, Rarity.RARE, mage.cards.a.AngelfireIgnition.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Angelfire Ignition", 367, Rarity.RARE, mage.cards.a.AngelfireIgnition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angelic Enforcer", 17, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Angelic Enforcer", 327, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Infusion", 210, Rarity.UNCOMMON, mage.cards.a.ArcaneInfusion.class)); - cards.add(new SetCardInfo("Archive Haunt", 68, Rarity.UNCOMMON, mage.cards.a.ArchiveHaunt.class)); cards.add(new SetCardInfo("Ardent Elementalist", 128, Rarity.COMMON, mage.cards.a.ArdentElementalist.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 211, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 279, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 307, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 211, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 279, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 307, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arrogant Outlaw", 84, Rarity.COMMON, mage.cards.a.ArrogantOutlaw.class)); - cards.add(new SetCardInfo("Ashmouth Dragon", 159, Rarity.RARE, mage.cards.a.AshmouthDragon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashmouth Dragon", 358, Rarity.RARE, mage.cards.a.AshmouthDragon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Augur of Autumn", 168, Rarity.RARE, mage.cards.a.AugurOfAutumn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Augur of Autumn", 360, Rarity.RARE, mage.cards.a.AugurOfAutumn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 100, Rarity.COMMON, mage.cards.a.AwokenDemon.class)); cards.add(new SetCardInfo("Baithook Angler", 42, Rarity.COMMON, mage.cards.b.BaithookAngler.class)); cards.add(new SetCardInfo("Baneblade Scoundrel", 289, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baneblade Scoundrel", 85, Rarity.UNCOMMON, mage.cards.b.BanebladeScoundrel.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Baneclaw Marauder", 289, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Baneclaw Marauder", 85, Rarity.UNCOMMON, mage.cards.b.BaneclawMarauder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bat Whisperer", 86, Rarity.COMMON, mage.cards.b.BatWhisperer.class)); cards.add(new SetCardInfo("Beloved Beggar", 3, Rarity.UNCOMMON, mage.cards.b.BelovedBeggar.class)); - cards.add(new SetCardInfo("Benevolent Geist", 336, Rarity.RARE, mage.cards.b.BenevolentGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Benevolent Geist", 61, Rarity.RARE, mage.cards.b.BenevolentGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bereaved Survivor", 4, Rarity.UNCOMMON, mage.cards.b.BereavedSurvivor.class)); cards.add(new SetCardInfo("Bird Admirer", 169, Rarity.COMMON, mage.cards.b.BirdAdmirer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bird Admirer", 298, Rarity.COMMON, mage.cards.b.BirdAdmirer.class, NON_FULL_USE_VARIOUS)); @@ -110,9 +97,7 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Champion of the Perished", 344, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Champion of the Perished", 385, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Champion of the Perished", 91, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chapel Shieldgeist", 13, Rarity.UNCOMMON, mage.cards.c.ChapelShieldgeist.class)); cards.add(new SetCardInfo("Chaplain of Alms", 13, Rarity.UNCOMMON, mage.cards.c.ChaplainOfAlms.class)); - cards.add(new SetCardInfo("Chilling Chronicle", 63, Rarity.UNCOMMON, mage.cards.c.ChillingChronicle.class)); cards.add(new SetCardInfo("Clarion Cathars", 14, Rarity.COMMON, mage.cards.c.ClarionCathars.class)); cards.add(new SetCardInfo("Clear Shot", 176, Rarity.UNCOMMON, mage.cards.c.ClearShot.class)); cards.add(new SetCardInfo("Component Collector", 43, Rarity.COMMON, mage.cards.c.ComponentCollector.class)); @@ -124,10 +109,7 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Corpse Cobble", 214, Rarity.UNCOMMON, mage.cards.c.CorpseCobble.class)); cards.add(new SetCardInfo("Covert Cutpurse", 92, Rarity.UNCOMMON, mage.cards.c.CovertCutpurse.class)); cards.add(new SetCardInfo("Covetous Castaway", 45, Rarity.UNCOMMON, mage.cards.c.CovetousCastaway.class)); - cards.add(new SetCardInfo("Covetous Geist", 92, Rarity.UNCOMMON, mage.cards.c.CovetousGeist.class)); cards.add(new SetCardInfo("Crawl from the Cellar", 93, Rarity.COMMON, mage.cards.c.CrawlFromTheCellar.class)); - cards.add(new SetCardInfo("Creeping Inn", 264, Rarity.MYTHIC, mage.cards.c.CreepingInn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Creeping Inn", 379, Rarity.MYTHIC, mage.cards.c.CreepingInn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Croaking Counterpart", 215, Rarity.RARE, mage.cards.c.CroakingCounterpart.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Croaking Counterpart", 369, Rarity.RARE, mage.cards.c.CroakingCounterpart.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Crossroads Candleguide", 253, Rarity.COMMON, mage.cards.c.CrossroadsCandleguide.class)); @@ -139,31 +121,22 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Curse of Silence", 326, Rarity.RARE, mage.cards.c.CurseOfSilence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Curse of Surveillance", 334, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Curse of Surveillance", 46, Rarity.RARE, mage.cards.c.CurseOfSurveillance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dauntless Avenger", 4, Rarity.UNCOMMON, mage.cards.d.DauntlessAvenger.class)); cards.add(new SetCardInfo("Dawnhart Mentor", 179, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Mentor", 300, Rarity.UNCOMMON, mage.cards.d.DawnhartMentor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 180, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Rejuvenator", 301, Rarity.COMMON, mage.cards.d.DawnhartRejuvenator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Wardens", 216, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dawnhart Wardens", 308, Rarity.UNCOMMON, mage.cards.d.DawnhartWardens.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deathbonnet Hulk", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetHulk.class)); cards.add(new SetCardInfo("Deathbonnet Sprout", 181, Rarity.UNCOMMON, mage.cards.d.DeathbonnetSprout.class)); cards.add(new SetCardInfo("Defend the Celestus", 182, Rarity.UNCOMMON, mage.cards.d.DefendTheCelestus.class)); cards.add(new SetCardInfo("Defenestrate", 95, Rarity.COMMON, mage.cards.d.Defenestrate.class)); cards.add(new SetCardInfo("Delver of Secrets", 47, Rarity.UNCOMMON, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 217, Rarity.RARE, mage.cards.d.DennickPiousApparition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dennick, Pious Apparition", 317, Rarity.RARE, mage.cards.d.DennickPiousApparition.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 217, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dennick, Pious Apprentice", 317, Rarity.RARE, mage.cards.d.DennickPiousApprentice.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Departed Soulkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DepartedSoulkeeper.class)); cards.add(new SetCardInfo("Deserted Beach", 260, Rarity.RARE, mage.cards.d.DesertedBeach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deserted Beach", 281, Rarity.RARE, mage.cards.d.DesertedBeach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Devious Cover-Up", 48, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); cards.add(new SetCardInfo("Devoted Grafkeeper", 218, Rarity.UNCOMMON, mage.cards.d.DevotedGrafkeeper.class)); - cards.add(new SetCardInfo("Dire-Strain Brawler", 203, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Brawler", 305, Rarity.COMMON, mage.cards.d.DireStrainBrawler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 174, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Demolisher", 299, Rarity.UNCOMMON, mage.cards.d.DireStrainDemolisher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire-Strain Rampage", 219, Rarity.RARE, mage.cards.d.DireStrainRampage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire-Strain Rampage", 370, Rarity.RARE, mage.cards.d.DireStrainRampage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diregraf Horde", 96, Rarity.COMMON, mage.cards.d.DiregrafHorde.class)); @@ -179,7 +152,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Eccentric Farmer", 185, Rarity.COMMON, mage.cards.e.EccentricFarmer.class)); cards.add(new SetCardInfo("Ecstatic Awakener", 100, Rarity.COMMON, mage.cards.e.EcstaticAwakener.class)); cards.add(new SetCardInfo("Electric Revelation", 135, Rarity.COMMON, mage.cards.e.ElectricRevelation.class)); - cards.add(new SetCardInfo("Embodiment of Flame", 141, Rarity.UNCOMMON, mage.cards.e.EmbodimentOfFlame.class)); cards.add(new SetCardInfo("Enduring Angel", 17, Rarity.MYTHIC, mage.cards.e.EnduringAngel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Enduring Angel", 327, Rarity.MYTHIC, mage.cards.e.EnduringAngel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Evolving Wilds", 261, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); @@ -192,8 +164,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Famished Foragers", 138, Rarity.COMMON, mage.cards.f.FamishedForagers.class)); cards.add(new SetCardInfo("Fangblade Brigand", 139, Rarity.UNCOMMON, mage.cards.f.FangbladeBrigand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fangblade Brigand", 292, Rarity.UNCOMMON, mage.cards.f.FangbladeBrigand.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fangblade Eviscerator", 139, Rarity.UNCOMMON, mage.cards.f.FangbladeEviscerator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fangblade Eviscerator", 292, Rarity.UNCOMMON, mage.cards.f.FangbladeEviscerator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fateful Absence", 18, Rarity.RARE, mage.cards.f.FatefulAbsence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fateful Absence", 328, Rarity.RARE, mage.cards.f.FatefulAbsence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Festival Crasher", 140, Rarity.COMMON, mage.cards.f.FestivalCrasher.class)); @@ -209,8 +179,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Forest", 277, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 384, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Foul Play", 101, Rarity.UNCOMMON, mage.cards.f.FoulPlay.class)); - cards.add(new SetCardInfo("Frenzied Trapbreaker", 190, Rarity.UNCOMMON, mage.cards.f.FrenziedTrapbreaker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Frenzied Trapbreaker", 303, Rarity.UNCOMMON, mage.cards.f.FrenziedTrapbreaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Galedrifter", 55, Rarity.COMMON, mage.cards.g.Galedrifter.class)); cards.add(new SetCardInfo("Galvanic Iteration", 224, Rarity.RARE, mage.cards.g.GalvanicIteration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Galvanic Iteration", 371, Rarity.RARE, mage.cards.g.GalvanicIteration.class, NON_FULL_USE_VARIOUS)); @@ -221,8 +189,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Geistflame Reservoir", 142, Rarity.RARE, mage.cards.g.GeistflameReservoir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geistflame Reservoir", 355, Rarity.RARE, mage.cards.g.GeistflameReservoir.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geistwave", 56, Rarity.COMMON, mage.cards.g.Geistwave.class)); - cards.add(new SetCardInfo("Generous Soul", 3, Rarity.UNCOMMON, mage.cards.g.GenerousSoul.class)); - cards.add(new SetCardInfo("Ghostly Castigator", 45, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 225, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulcaller's Harvest", 372, Rarity.RARE, mage.cards.g.GhoulcallersHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 102, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class)); @@ -230,15 +196,11 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Gisa, Glorious Resurrector", 314, Rarity.RARE, mage.cards.g.GisaGloriousResurrector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grafted Identity", 335, Rarity.RARE, mage.cards.g.GraftedIdentity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grafted Identity", 57, Rarity.RARE, mage.cards.g.GraftedIdentity.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Graveyard Glutton", 104, Rarity.RARE, mage.cards.g.GraveyardGlutton.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Graveyard Glutton", 290, Rarity.RARE, mage.cards.g.GraveyardGlutton.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Graveyard Trespasser", 104, Rarity.RARE, mage.cards.g.GraveyardTrespasser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Graveyard Trespasser", 290, Rarity.RARE, mage.cards.g.GraveyardTrespasser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grizzly Ghoul", 226, Rarity.UNCOMMON, mage.cards.g.GrizzlyGhoul.class)); cards.add(new SetCardInfo("Hallowed Respite", 227, Rarity.RARE, mage.cards.h.HallowedRespite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Respite", 373, Rarity.RARE, mage.cards.h.HallowedRespite.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Harvesttide Assailant", 143, Rarity.COMMON, mage.cards.h.HarvesttideAssailant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Harvesttide Assailant", 293, Rarity.COMMON, mage.cards.h.HarvesttideAssailant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Harvesttide Infiltrator", 143, Rarity.COMMON, mage.cards.h.HarvesttideInfiltrator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Harvesttide Infiltrator", 293, Rarity.COMMON, mage.cards.h.HarvesttideInfiltrator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Harvesttide Sentry", 186, Rarity.COMMON, mage.cards.h.HarvesttideSentry.class)); @@ -248,7 +210,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Heirloom Mirror", 105, Rarity.UNCOMMON, mage.cards.h.HeirloomMirror.class)); cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class)); cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class)); - cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class)); cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hostile Hostel", 379, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hound Tamer", 187, Rarity.UNCOMMON, mage.cards.h.HoundTamer.class, NON_FULL_USE_VARIOUS)); @@ -258,8 +219,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Immolation", 144, Rarity.COMMON, mage.cards.i.Immolation.class)); cards.add(new SetCardInfo("Infernal Grasp", 107, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 389, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inherited Fiend", 105, Rarity.UNCOMMON, mage.cards.i.InheritedFiend.class)); - cards.add(new SetCardInfo("Insectile Aberration", 47, Rarity.UNCOMMON, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Intrepid Adversary", 25, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Intrepid Adversary", 329, Rarity.MYTHIC, mage.cards.i.IntrepidAdversary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 270, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); @@ -278,8 +237,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Kessig Naturalist", 310, Rarity.UNCOMMON, mage.cards.k.KessigNaturalist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lambholt Harrier", 145, Rarity.COMMON, mage.cards.l.LambholtHarrier.class)); cards.add(new SetCardInfo("Larder Zombie", 58, Rarity.COMMON, mage.cards.l.LarderZombie.class)); - cards.add(new SetCardInfo("Leeching Lurker", 345, Rarity.RARE, mage.cards.l.LeechingLurker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Leeching Lurker", 94, Rarity.RARE, mage.cards.l.LeechingLurker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 313, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lier, Disciple of the Drowned", 59, Rarity.MYTHIC, mage.cards.l.LierDiscipleOfTheDrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 232, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, NON_FULL_USE_VARIOUS)); @@ -289,12 +246,9 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Locked in the Cemetery", 60, Rarity.COMMON, mage.cards.l.LockedInTheCemetery.class)); cards.add(new SetCardInfo("Lord of the Forsaken", 110, Rarity.MYTHIC, mage.cards.l.LordOfTheForsaken.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lord of the Forsaken", 346, Rarity.MYTHIC, mage.cards.l.LordOfTheForsaken.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of the Ulvenwald", 231, Rarity.UNCOMMON, mage.cards.l.LordOfTheUlvenwald.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of the Ulvenwald", 310, Rarity.UNCOMMON, mage.cards.l.LordOfTheUlvenwald.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Loyal Gryff", 26, Rarity.UNCOMMON, mage.cards.l.LoyalGryff.class)); cards.add(new SetCardInfo("Ludevic, Necrogenius", 233, Rarity.RARE, mage.cards.l.LudevicNecrogenius.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ludevic, Necrogenius", 320, Rarity.RARE, mage.cards.l.LudevicNecrogenius.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Luminous Phantom", 27, Rarity.COMMON, mage.cards.l.LuminousPhantom.class)); cards.add(new SetCardInfo("Lunar Frenzy", 147, Rarity.UNCOMMON, mage.cards.l.LunarFrenzy.class)); cards.add(new SetCardInfo("Lunarch Veteran", 27, Rarity.COMMON, mage.cards.l.LunarchVeteran.class)); cards.add(new SetCardInfo("Malevolent Hermit", 336, Rarity.RARE, mage.cards.m.MalevolentHermit.class, NON_FULL_USE_VARIOUS)); @@ -304,22 +258,18 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Memory Deluge", 337, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Memory Deluge", 62, Rarity.RARE, mage.cards.m.MemoryDeluge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Might of the Old Ways", 189, Rarity.COMMON, mage.cards.m.MightOfTheOldWays.class)); - cards.add(new SetCardInfo("Moonrage Brute", 286, Rarity.RARE, mage.cards.m.MoonrageBrute.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Moonrage Brute", 7, Rarity.RARE, mage.cards.m.MoonrageBrute.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Moonrager's Slash", 148, Rarity.COMMON, mage.cards.m.MoonragersSlash.class)); cards.add(new SetCardInfo("Moonsilver Key", 255, Rarity.UNCOMMON, mage.cards.m.MoonsilverKey.class)); cards.add(new SetCardInfo("Moonveil Regent", 149, Rarity.MYTHIC, mage.cards.m.MoonveilRegent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Moonveil Regent", 357, Rarity.MYTHIC, mage.cards.m.MoonveilRegent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morbid Opportunist", 113, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class)); cards.add(new SetCardInfo("Morkrut Behemoth", 114, Rarity.COMMON, mage.cards.m.MorkrutBehemoth.class)); - cards.add(new SetCardInfo("Morning Apparition", 28, Rarity.COMMON, mage.cards.m.MorningApparition.class)); cards.add(new SetCardInfo("Mountain", 274, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 275, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 383, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mounted Dreadknight", 150, Rarity.COMMON, mage.cards.m.MountedDreadknight.class)); cards.add(new SetCardInfo("Mourning Patrol", 28, Rarity.COMMON, mage.cards.m.MourningPatrol.class)); cards.add(new SetCardInfo("Mysterious Tome", 63, Rarity.UNCOMMON, mage.cards.m.MysteriousTome.class)); - cards.add(new SetCardInfo("Mystic Monstrosity", 256, Rarity.UNCOMMON, mage.cards.m.MysticMonstrosity.class)); cards.add(new SetCardInfo("Mystic Skull", 256, Rarity.UNCOMMON, mage.cards.m.MysticSkull.class)); cards.add(new SetCardInfo("Nebelgast Intruder", 64, Rarity.UNCOMMON, mage.cards.n.NebelgastIntruder.class)); cards.add(new SetCardInfo("Necrosynthesis", 115, Rarity.UNCOMMON, mage.cards.n.Necrosynthesis.class)); @@ -328,15 +278,11 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Novice Occultist", 117, Rarity.COMMON, mage.cards.n.NoviceOccultist.class)); cards.add(new SetCardInfo("Obsessive Astronomer", 152, Rarity.UNCOMMON, mage.cards.o.ObsessiveAstronomer.class)); cards.add(new SetCardInfo("Odric's Outrider", 29, Rarity.UNCOMMON, mage.cards.o.OdricsOutrider.class)); - cards.add(new SetCardInfo("Olag, Ludevic's Hubris", 233, Rarity.RARE, mage.cards.o.OlagLudevicsHubris.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Olag, Ludevic's Hubris", 320, Rarity.RARE, mage.cards.o.OlagLudevicsHubris.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Old Stickfingers", 234, Rarity.RARE, mage.cards.o.OldStickfingers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Old Stickfingers", 321, Rarity.RARE, mage.cards.o.OldStickfingers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Olivia's Midnight Ambush", 118, Rarity.COMMON, mage.cards.o.OliviasMidnightAmbush.class)); cards.add(new SetCardInfo("Ominous Roost", 65, Rarity.UNCOMMON, mage.cards.o.OminousRoost.class)); cards.add(new SetCardInfo("Organ Hoarder", 66, Rarity.COMMON, mage.cards.o.OrganHoarder.class)); - cards.add(new SetCardInfo("Ormendahl, the Corrupter", 109, Rarity.MYTHIC, mage.cards.o.OrmendahlTheCorrupter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ormendahl, the Corrupter", 316, Rarity.MYTHIC, mage.cards.o.OrmendahlTheCorrupter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Otherworldly Gaze", 67, Rarity.COMMON, mage.cards.o.OtherworldlyGaze.class)); cards.add(new SetCardInfo("Outland Liberator", 190, Rarity.UNCOMMON, mage.cards.o.OutlandLiberator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Outland Liberator", 303, Rarity.UNCOMMON, mage.cards.o.OutlandLiberator.class, NON_FULL_USE_VARIOUS)); @@ -357,8 +303,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Play with Fire", 154, Rarity.UNCOMMON, mage.cards.p.PlayWithFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Play with Fire", 390, Rarity.UNCOMMON, mage.cards.p.PlayWithFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plummet", 193, Rarity.COMMON, mage.cards.p.Plummet.class)); - cards.add(new SetCardInfo("Poppet Factory", 339, Rarity.MYTHIC, mage.cards.p.PoppetFactory.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Poppet Factory", 71, Rarity.MYTHIC, mage.cards.p.PoppetFactory.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Poppet Stitcher", 339, Rarity.MYTHIC, mage.cards.p.PoppetStitcher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Poppet Stitcher", 71, Rarity.MYTHIC, mage.cards.p.PoppetStitcher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Primal Adversary", 194, Rarity.MYTHIC, mage.cards.p.PrimalAdversary.class, NON_FULL_USE_VARIOUS)); @@ -384,10 +328,7 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Sacred Fire", 239, Rarity.UNCOMMON, mage.cards.s.SacredFire.class)); cards.add(new SetCardInfo("Saryth, the Viper's Fang", 197, Rarity.RARE, mage.cards.s.SarythTheVipersFang.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Saryth, the Viper's Fang", 304, Rarity.RARE, mage.cards.s.SarythTheVipersFang.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Seafaring Werewolf", 288, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Seafaring Werewolf", 80, Rarity.RARE, mage.cards.s.SeafaringWerewolf.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Search Party Captain", 32, Rarity.COMMON, mage.cards.s.SearchPartyCaptain.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 2, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class)); cards.add(new SetCardInfo("Secrets of the Key", 73, Rarity.COMMON, mage.cards.s.SecretsOfTheKey.class)); cards.add(new SetCardInfo("Seize the Storm", 158, Rarity.UNCOMMON, mage.cards.s.SeizeTheStorm.class)); cards.add(new SetCardInfo("Shadowbeast Sighting", 198, Rarity.COMMON, mage.cards.s.ShadowbeastSighting.class)); @@ -419,21 +360,14 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Soul-Guide Gryff", 35, Rarity.COMMON, mage.cards.s.SoulGuideGryff.class)); cards.add(new SetCardInfo("Spectral Adversary", 341, Rarity.MYTHIC, mage.cards.s.SpectralAdversary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spectral Adversary", 77, Rarity.MYTHIC, mage.cards.s.SpectralAdversary.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Spellrune Howler", 160, Rarity.UNCOMMON, mage.cards.s.SpellruneHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Spellrune Howler", 295, Rarity.UNCOMMON, mage.cards.s.SpellruneHowler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spellrune Painter", 160, Rarity.UNCOMMON, mage.cards.s.SpellrunePainter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spellrune Painter", 295, Rarity.UNCOMMON, mage.cards.s.SpellrunePainter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Stalking Predator", 120, Rarity.COMMON, mage.cards.s.StalkingPredator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Stalking Predator", 291, Rarity.COMMON, mage.cards.s.StalkingPredator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Startle", 78, Rarity.COMMON, mage.cards.s.Startle.class)); cards.add(new SetCardInfo("Stolen Vitality", 161, Rarity.COMMON, mage.cards.s.StolenVitality.class)); cards.add(new SetCardInfo("Storm Skreelix", 243, Rarity.UNCOMMON, mage.cards.s.StormSkreelix.class)); cards.add(new SetCardInfo("Storm the Festival", 200, Rarity.RARE, mage.cards.s.StormTheFestival.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Storm the Festival", 364, Rarity.RARE, mage.cards.s.StormTheFestival.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm-Charged Slasher", 157, Rarity.RARE, mage.cards.s.StormChargedSlasher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm-Charged Slasher", 294, Rarity.RARE, mage.cards.s.StormChargedSlasher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stormrider Spirit", 79, Rarity.COMMON, mage.cards.s.StormriderSpirit.class)); - cards.add(new SetCardInfo("Strangling Grasp", 126, Rarity.UNCOMMON, mage.cards.s.StranglingGrasp.class)); cards.add(new SetCardInfo("Stromkirk Bloodthief", 123, Rarity.UNCOMMON, mage.cards.s.StromkirkBloodthief.class)); cards.add(new SetCardInfo("Stuffed Bear", 259, Rarity.COMMON, mage.cards.s.StuffedBear.class)); cards.add(new SetCardInfo("Sungold Barrage", 36, Rarity.COMMON, mage.cards.s.SungoldBarrage.class)); @@ -453,8 +387,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Tapping at the Window", 201, Rarity.COMMON, mage.cards.t.TappingAtTheWindow.class)); cards.add(new SetCardInfo("Tavern Ruffian", 163, Rarity.COMMON, mage.cards.t.TavernRuffian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tavern Ruffian", 296, Rarity.COMMON, mage.cards.t.TavernRuffian.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tavern Smasher", 163, Rarity.COMMON, mage.cards.t.TavernSmasher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tavern Smasher", 296, Rarity.COMMON, mage.cards.t.TavernSmasher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi, Who Slows the Sunset", 245, Rarity.MYTHIC, mage.cards.t.TeferiWhoSlowsTheSunset.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi, Who Slows the Sunset", 280, Rarity.MYTHIC, mage.cards.t.TeferiWhoSlowsTheSunset.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Celestus", 252, Rarity.RARE, mage.cards.t.TheCelestus.class, NON_FULL_USE_VARIOUS)); @@ -468,12 +400,8 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Tireless Hauler", 305, Rarity.COMMON, mage.cards.t.TirelessHauler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tovolar's Huntmaster", 204, Rarity.RARE, mage.cards.t.TovolarsHuntmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tovolar's Huntmaster", 306, Rarity.RARE, mage.cards.t.TovolarsHuntmaster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tovolar's Packleader", 204, Rarity.RARE, mage.cards.t.TovolarsPackleader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tovolar's Packleader", 306, Rarity.RARE, mage.cards.t.TovolarsPackleader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tovolar, Dire Overlord", 246, Rarity.RARE, mage.cards.t.TovolarDireOverlord.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tovolar, Dire Overlord", 311, Rarity.RARE, mage.cards.t.TovolarDireOverlord.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tovolar, the Midnight Scourge", 246, Rarity.RARE, mage.cards.t.TovolarTheMidnightScourge.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tovolar, the Midnight Scourge", 311, Rarity.RARE, mage.cards.t.TovolarTheMidnightScourge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Triskaidekaphile", 342, Rarity.RARE, mage.cards.t.Triskaidekaphile.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Triskaidekaphile", 386, Rarity.RARE, mage.cards.t.Triskaidekaphile.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Triskaidekaphile", 81, Rarity.RARE, mage.cards.t.Triskaidekaphile.class, NON_FULL_USE_VARIOUS)); @@ -483,8 +411,6 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Unnatural Growth", 365, Rarity.RARE, mage.cards.u.UnnaturalGrowth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Unnatural Moonrise", 247, Rarity.UNCOMMON, mage.cards.u.UnnaturalMoonrise.class)); cards.add(new SetCardInfo("Unruly Mob", 40, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); - cards.add(new SetCardInfo("Untamed Pup", 187, Rarity.UNCOMMON, mage.cards.u.UntamedPup.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Untamed Pup", 302, Rarity.UNCOMMON, mage.cards.u.UntamedPup.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vadrik, Astral Archmage", 248, Rarity.RARE, mage.cards.v.VadrikAstralArchmage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vadrik, Astral Archmage", 325, Rarity.RARE, mage.cards.v.VadrikAstralArchmage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vampire Interloper", 125, Rarity.COMMON, mage.cards.v.VampireInterloper.class)); @@ -492,20 +418,15 @@ public final class InnistradMidnightHunt extends ExpansionSet { cards.add(new SetCardInfo("Vanquish the Horde", 333, Rarity.RARE, mage.cards.v.VanquishTheHorde.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vanquish the Horde", 41, Rarity.RARE, mage.cards.v.VanquishTheHorde.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vengeful Strangler", 126, Rarity.UNCOMMON, mage.cards.v.VengefulStrangler.class)); - cards.add(new SetCardInfo("Village Reavers", 165, Rarity.UNCOMMON, mage.cards.v.VillageReavers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Village Reavers", 297, Rarity.UNCOMMON, mage.cards.v.VillageReavers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Village Watch", 165, Rarity.UNCOMMON, mage.cards.v.VillageWatch.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Village Watch", 297, Rarity.UNCOMMON, mage.cards.v.VillageWatch.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vivisection", 83, Rarity.UNCOMMON, mage.cards.v.Vivisection.class)); cards.add(new SetCardInfo("Voldaren Ambusher", 166, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class)); cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class)); - cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class)); cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wake to Slaughter", 376, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Willow Geist", 366, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wing Shredder", 169, Rarity.COMMON, mage.cards.w.WingShredder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wing Shredder", 298, Rarity.COMMON, mage.cards.w.WingShredder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Winterthorn Blessing", 251, Rarity.UNCOMMON, mage.cards.w.WinterthornBlessing.class)); cards.add(new SetCardInfo("Wrenn and Seven", 208, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wrenn and Seven", 278, Rarity.MYTHIC, mage.cards.w.WrennAndSeven.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/InnistradPromos.java b/Mage.Sets/src/mage/sets/InnistradPromos.java index 7a0c46fd575..f118ae1429f 100644 --- a/Mage.Sets/src/mage/sets/InnistradPromos.java +++ b/Mage.Sets/src/mage/sets/InnistradPromos.java @@ -23,8 +23,6 @@ public class InnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Devil's Play", 140, Rarity.RARE, mage.cards.d.DevilsPlay.class)); cards.add(new SetCardInfo("Diregraf Ghoul", 97, Rarity.UNCOMMON, mage.cards.d.DiregrafGhoul.class)); cards.add(new SetCardInfo("Elite Inquisitor", 13, Rarity.RARE, mage.cards.e.EliteInquisitor.class)); - cards.add(new SetCardInfo("Howlpack Alpha", "193*", Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); - cards.add(new SetCardInfo("Ludevic's Abomination", "64*", Rarity.RARE, mage.cards.l.LudevicsAbomination.class)); cards.add(new SetCardInfo("Ludevic's Test Subject", "64*", Rarity.RARE, mage.cards.l.LudevicsTestSubject.class)); cards.add(new SetCardInfo("Mayor of Avabruck", "193*", Rarity.RARE, mage.cards.m.MayorOfAvabruck.class)); diff --git a/Mage.Sets/src/mage/sets/InnistradRemastered.java b/Mage.Sets/src/mage/sets/InnistradRemastered.java index cb192ab1fb0..f2644ce218f 100644 --- a/Mage.Sets/src/mage/sets/InnistradRemastered.java +++ b/Mage.Sets/src/mage/sets/InnistradRemastered.java @@ -33,13 +33,13 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Abundant Maw", 329, Rarity.COMMON, mage.cards.a.AbundantMaw.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Aim High", 185, Rarity.COMMON, mage.cards.a.AimHigh.class)); cards.add(new SetCardInfo("Alchemist's Greeting", 140, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Alchemist's Greeting", 393, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Alchemist's Greeting", 393, Rarity.COMMON, mage.cards.a.AlchemistsGreeting.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Altered Ego", 228, Rarity.RARE, mage.cards.a.AlteredEgo.class)); cards.add(new SetCardInfo("Ambitious Farmhand", 448, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ambitious Farmhand", 8, Rarity.UNCOMMON, mage.cards.a.AmbitiousFarmhand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ambush Viper", 186, Rarity.COMMON, mage.cards.a.AmbushViper.class)); cards.add(new SetCardInfo("Ancestral Anger", 141, Rarity.COMMON, mage.cards.a.AncestralAnger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ancestral Anger", 394, Rarity.COMMON, mage.cards.a.AncestralAnger.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ancestral Anger", 394, Rarity.COMMON, mage.cards.a.AncestralAnger.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Angel's Tomb", 253, Rarity.UNCOMMON, mage.cards.a.AngelsTomb.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Angel's Tomb", 438, Rarity.UNCOMMON, mage.cards.a.AngelsTomb.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Angelfire Ignition", 229, Rarity.RARE, mage.cards.a.AngelfireIgnition.class)); @@ -52,33 +52,18 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Archghoul of Thraben", 95, Rarity.UNCOMMON, mage.cards.a.ArchghoulOfThraben.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn Kord", 230, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn Kord", 324, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 230, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 324, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashmouth Blade", 269, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashmouth Blade", 473, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Asylum Visitor", 371, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Asylum Visitor", 96, Rarity.UNCOMMON, mage.cards.a.AsylumVisitor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aurora of Emrakul", 260, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aurora of Emrakul", 472, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacyn, Angel of Hope", 477, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacyn, Angel of Hope", 482, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 11, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 449, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Avacynian Priest", 12, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avacynian Priest", 334, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 107, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Demon", 462, Rarity.COMMON, mage.cards.a.AwokenDemon.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Horror", 460, Rarity.RARE, mage.cards.a.AwokenHorror.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Awoken Horror", 91, Rarity.RARE, mage.cards.a.AwokenHorror.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Balefire Dragon", 479, Rarity.MYTHIC, mage.cards.b.BalefireDragon.class, RETRO_ART)); - cards.add(new SetCardInfo("Bane of Hanweir", 158, Rarity.COMMON, mage.cards.b.BaneOfHanweir.class)); cards.add(new SetCardInfo("Battleground Geist", 53, Rarity.COMMON, mage.cards.b.BattlegroundGeist.class)); cards.add(new SetCardInfo("Bedlam Reveler", 142, Rarity.RARE, mage.cards.b.BedlamReveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bedlam Reveler", 312, Rarity.RARE, mage.cards.b.BedlamReveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Biolume Egg", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Biolume Egg", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeEgg.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Biolume Serpent", 455, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Biolume Serpent", 54, Rarity.UNCOMMON, mage.cards.b.BiolumeSerpent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bladestitched Skaab", 231, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bladestitched Skaab", 426, Rarity.UNCOMMON, mage.cards.b.BladestitchedSkaab.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Blazing Torch", 254, Rarity.COMMON, mage.cards.b.BlazingTorch.class)); @@ -86,22 +71,19 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Blood Artist", 372, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Artist", 97, Rarity.UNCOMMON, mage.cards.b.BloodArtist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Mist", 143, Rarity.UNCOMMON, mage.cards.b.BloodMist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Blood Mist", 395, Rarity.UNCOMMON, mage.cards.b.BloodMist.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Blood Mist", 395, Rarity.UNCOMMON, mage.cards.b.BloodMist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Petal Celebrant", 144, Rarity.COMMON, mage.cards.b.BloodPetalCelebrant.class)); - cards.add(new SetCardInfo("Bloodbat Summoner", 138, Rarity.RARE, mage.cards.b.BloodbatSummoner.class)); cards.add(new SetCardInfo("Bloodhall Priest", 232, Rarity.RARE, mage.cards.b.BloodhallPriest.class)); cards.add(new SetCardInfo("Bloodline Keeper", 327, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 461, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 98, Rarity.MYTHIC, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodmad Vampire", 145, Rarity.COMMON, mage.cards.b.BloodmadVampire.class)); - cards.add(new SetCardInfo("Bloodsoaked Reveler", 128, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bloodsoaked Reveler", 463, Rarity.UNCOMMON, mage.cards.b.BloodsoakedReveler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodtithe Harvester", 233, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodtithe Harvester", 427, Rarity.UNCOMMON, mage.cards.b.BloodtitheHarvester.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Boarded Window", 255, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Boarded Window", 439, Rarity.UNCOMMON, mage.cards.b.BoardedWindow.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Borrowed Hostility", 146, Rarity.COMMON, mage.cards.b.BorrowedHostility.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Borrowed Hostility", 396, Rarity.COMMON, mage.cards.b.BorrowedHostility.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Borrowed Hostility", 396, Rarity.COMMON, mage.cards.b.BorrowedHostility.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Bound by Moonsilver", 13, Rarity.COMMON, mage.cards.b.BoundByMoonsilver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bound by Moonsilver", 335, Rarity.COMMON, mage.cards.b.BoundByMoonsilver.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Bramble Wurm", 187, Rarity.COMMON, mage.cards.b.BrambleWurm.class, NON_FULL_USE_VARIOUS)); @@ -109,7 +91,7 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "14b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class)); cards.add(new SetCardInfo("Bruna, the Fading Light", 14, Rarity.RARE, mage.cards.b.BrunaTheFadingLight.class)); cards.add(new SetCardInfo("Burning Vengeance", 147, Rarity.UNCOMMON, mage.cards.b.BurningVengeance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Burning Vengeance", 397, Rarity.UNCOMMON, mage.cards.b.BurningVengeance.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Burning Vengeance", 397, Rarity.UNCOMMON, mage.cards.b.BurningVengeance.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Butcher Ghoul", 373, Rarity.COMMON, mage.cards.b.ButcherGhoul.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Butcher Ghoul", 99, Rarity.COMMON, mage.cards.b.ButcherGhoul.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Butcher's Cleaver", 256, Rarity.UNCOMMON, mage.cards.b.ButchersCleaver.class, NON_FULL_USE_VARIOUS)); @@ -125,14 +107,10 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Cathars' Crusade", 17, Rarity.RARE, mage.cards.c.CatharsCrusade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cathars' Crusade", 337, Rarity.RARE, mage.cards.c.CatharsCrusade.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Cathars' Crusade", 483, Rarity.RARE, mage.cards.c.CatharsCrusade.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Chalice of Death", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chalice of Death", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfDeath.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chalice of Life", 257, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chalice of Life", 471, Rarity.UNCOMMON, mage.cards.c.ChaliceOfLife.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra, Dressed to Kill", 148, Rarity.MYTHIC, mage.cards.c.ChandraDressedToKill.class)); cards.add(new SetCardInfo("Chittering Host", "123b", Rarity.COMMON, mage.cards.c.ChitteringHost.class)); - cards.add(new SetCardInfo("Cipherbound Spirit", 459, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Cipherbound Spirit", 85, Rarity.UNCOMMON, mage.cards.c.CipherboundSpirit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Clear Shot", 188, Rarity.UNCOMMON, mage.cards.c.ClearShot.class)); cards.add(new SetCardInfo("Cobbled Lancer", 56, Rarity.UNCOMMON, mage.cards.c.CobbledLancer.class)); cards.add(new SetCardInfo("Cobbled Wings", 258, Rarity.COMMON, mage.cards.c.CobbledWings.class)); @@ -141,7 +119,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Collective Brutality", 375, Rarity.RARE, mage.cards.c.CollectiveBrutality.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Collective Defiance", 149, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Compelling Deterrence", 57, Rarity.UNCOMMON, mage.cards.c.CompellingDeterrence.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 150, Rarity.COMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 150, Rarity.COMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Conjurer's Closet", 259, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Conjurer's Closet", 321, Rarity.RARE, mage.cards.c.ConjurersCloset.class, NON_FULL_USE_VARIOUS)); @@ -169,14 +146,12 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Deadly Allure", 103, Rarity.UNCOMMON, mage.cards.d.DeadlyAllure.class)); cards.add(new SetCardInfo("Deathcap Glade", 275, Rarity.RARE, mage.cards.d.DeathcapGlade.class)); cards.add(new SetCardInfo("Decimator of the Provinces", 2, Rarity.RARE, mage.cards.d.DecimatorOfTheProvinces.class)); - cards.add(new SetCardInfo("Deluge of the Dead", 120, Rarity.RARE, mage.cards.d.DelugeOfTheDead.class)); cards.add(new SetCardInfo("Delver of Secrets", 457, Rarity.COMMON, mage.cards.d.DelverOfSecrets.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Delver of Secrets", 60, Rarity.COMMON, mage.cards.d.DelverOfSecrets.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Taskmaster", 104, Rarity.UNCOMMON, mage.cards.d.DemonicTaskmaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonic Taskmaster", 377, Rarity.UNCOMMON, mage.cards.d.DemonicTaskmaster.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Demonmail Hauberk", 261, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Demonmail Hauberk", 442, Rarity.UNCOMMON, mage.cards.d.DemonmailHauberk.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Depraved Harvester", 105, Rarity.COMMON, mage.cards.d.DepravedHarvester.class)); cards.add(new SetCardInfo("Deranged Assistant", 61, Rarity.COMMON, mage.cards.d.DerangedAssistant.class)); cards.add(new SetCardInfo("Deserted Beach", 276, Rarity.RARE, mage.cards.d.DesertedBeach.class)); cards.add(new SetCardInfo("Desperate Farmer", 105, Rarity.COMMON, mage.cards.d.DesperateFarmer.class)); @@ -205,8 +180,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Emrakul, the Promised End", 481, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Emrakul, the Promised End", 5, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Epitaph Golem", 262, Rarity.COMMON, mage.cards.e.EpitaphGolem.class)); - cards.add(new SetCardInfo("Erupting Dreadwolf", 171, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Erupting Dreadwolf", 465, Rarity.UNCOMMON, mage.cards.e.EruptingDreadwolf.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Essence Flux", 354, Rarity.COMMON, mage.cards.e.EssenceFlux.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Essence Flux", 64, Rarity.COMMON, mage.cards.e.EssenceFlux.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Evolving Wilds", 278, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); @@ -219,7 +192,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Fiend Hunter", 22, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fiend Hunter", 340, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Fiery Temper", 154, Rarity.UNCOMMON, mage.cards.f.FieryTemper.class)); - cards.add(new SetCardInfo("Final Iteration", 62, Rarity.RARE, mage.cards.f.FinalIteration.class)); cards.add(new SetCardInfo("Fleshtaker", 235, Rarity.UNCOMMON, mage.cards.f.Fleshtaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fleshtaker", 429, Rarity.UNCOMMON, mage.cards.f.Fleshtaker.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Forbidden Alchemy", 355, Rarity.UNCOMMON, mage.cards.f.ForbiddenAlchemy.class, RETRO_ART_USE_VARIOUS)); @@ -232,7 +204,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Galvanic Juggernaut", 263, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Galvanic Juggernaut", 443, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Garruk Relentless", 197, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); - cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 197, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); cards.add(new SetCardInfo("Gather the Townsfolk", 23, Rarity.COMMON, mage.cards.g.GatherTheTownsfolk.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gather the Townsfolk", 341, Rarity.COMMON, mage.cards.g.GatherTheTownsfolk.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Geier Reach Bandit", 156, Rarity.UNCOMMON, mage.cards.g.GeierReachBandit.class, NON_FULL_USE_VARIOUS)); @@ -240,8 +211,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Geistcatcher's Rig", 264, Rarity.UNCOMMON, mage.cards.g.GeistcatchersRig.class)); cards.add(new SetCardInfo("Geistlight Snare", 356, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Geistlight Snare", 66, Rarity.UNCOMMON, mage.cards.g.GeistlightSnare.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghostly Castigator", 456, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghostly Castigator", 58, Rarity.UNCOMMON, mage.cards.g.GhostlyCastigator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 110, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoulish Procession", 378, Rarity.UNCOMMON, mage.cards.g.GhoulishProcession.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ghoultree", 198, Rarity.UNCOMMON, mage.cards.g.Ghoultree.class, NON_FULL_USE_VARIOUS)); @@ -255,13 +224,11 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Grapple with the Past", 199, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grapple with the Past", 412, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Gravecrawler", 114, Rarity.RARE, mage.cards.g.Gravecrawler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gravecrawler", 380, Rarity.RARE, mage.cards.g.Gravecrawler.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Gravecrawler", 380, Rarity.RARE, mage.cards.g.Gravecrawler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Grimgrin, Corpse-Born", 239, Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class)); cards.add(new SetCardInfo("Griselbrand", 115, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Griselbrand", 381, Rarity.MYTHIC, mage.cards.g.Griselbrand.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Griselbrand", 381, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Griselbrand", 485, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Grisly Anglerfish", 458, Rarity.UNCOMMON, mage.cards.g.GrislyAnglerfish.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Grisly Anglerfish", 67, Rarity.UNCOMMON, mage.cards.g.GrislyAnglerfish.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grizzled Angler", 458, Rarity.UNCOMMON, mage.cards.g.GrizzledAngler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Grizzled Angler", 67, Rarity.UNCOMMON, mage.cards.g.GrizzledAngler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grizzly Ghoul", 240, Rarity.UNCOMMON, mage.cards.g.GrizzlyGhoul.class)); @@ -277,11 +244,11 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Hanweir, the Writhing Township", "157b", Rarity.RARE, mage.cards.h.HanweirTheWrithingTownship.class)); cards.add(new SetCardInfo("Harvest Hand", 265, Rarity.COMMON, mage.cards.h.HarvestHand.class)); cards.add(new SetCardInfo("Haunted Dead", 116, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Haunted Dead", 382, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Haunted Dead", 382, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Haunted Ridge", 280, Rarity.RARE, mage.cards.h.HauntedRidge.class)); cards.add(new SetCardInfo("Heartless Summoning", 117, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heartless Summoning", 309, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Heartless Summoning", 383, Rarity.RARE, mage.cards.h.HeartlessSummoning.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Heartless Summoning", 383, Rarity.RARE, mage.cards.h.HeartlessSummoning.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Helvault", 266, Rarity.RARE, mage.cards.h.Helvault.class)); cards.add(new SetCardInfo("Hermit Druid", 202, Rarity.RARE, mage.cards.h.HermitDruid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hermit Druid", 488, Rarity.RARE, mage.cards.h.HermitDruid.class, FULL_ART_USE_VARIOUS)); @@ -289,10 +256,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Honeymoon Hearse", 159, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class)); cards.add(new SetCardInfo("Hopeful Initiate", 27, Rarity.RARE, mage.cards.h.HopefulInitiate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hopeful Initiate", 343, Rarity.RARE, mage.cards.h.HopefulInitiate.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Howling Chorus", 214, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Howling Chorus", 469, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Howlpack Alpha", 207, Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); - cards.add(new SetCardInfo("Howlpack of Estwald", 224, Rarity.COMMON, mage.cards.h.HowlpackOfEstwald.class)); cards.add(new SetCardInfo("Howlpack Resurgence", 204, Rarity.UNCOMMON, mage.cards.h.HowlpackResurgence.class)); cards.add(new SetCardInfo("Hullbreaker Horror", 303, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hullbreaker Horror", 357, Rarity.RARE, mage.cards.h.HullbreakerHorror.class, RETRO_ART_USE_VARIOUS)); @@ -303,15 +266,11 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Huntmaster of the Fells", 470, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Imprisoned in the Moon", 358, Rarity.COMMON, mage.cards.i.ImprisonedInTheMoon.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Imprisoned in the Moon", 69, Rarity.COMMON, mage.cards.i.ImprisonedInTheMoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Incited Rabble", 451, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Incited Rabble", 46, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Indulgent Aristocrat", 384, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Indulgent Aristocrat", 384, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 119, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Infernal Grasp", 310, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Infernal Grasp", 385, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class,RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Insectile Aberration", 457, Rarity.COMMON, mage.cards.i.InsectileAberration.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Insectile Aberration", 60, Rarity.COMMON, mage.cards.i.InsectileAberration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Infernal Grasp", 385, Rarity.UNCOMMON, mage.cards.i.InfernalGrasp.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Inspiring Captain", 28, Rarity.COMMON, mage.cards.i.InspiringCaptain.class)); cards.add(new SetCardInfo("Intangible Virtue", 29, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); cards.add(new SetCardInfo("Intrepid Provisioner", 205, Rarity.COMMON, mage.cards.i.IntrepidProvisioner.class)); @@ -324,31 +283,22 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Join the Dance", 242, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Join the Dance", 432, Rarity.UNCOMMON, mage.cards.j.JoinTheDance.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Killing Wave", 121, Rarity.UNCOMMON, mage.cards.k.KillingWave.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Killing Wave", 386, Rarity.UNCOMMON, mage.cards.k.KillingWave.class,RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 193, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 323, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krallenhorde Howler", 467, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class, RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Killing Wave", 386, Rarity.UNCOMMON, mage.cards.k.KillingWave.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Kruin Outlaw", 161, Rarity.RARE, mage.cards.k.KruinOutlaw.class)); cards.add(new SetCardInfo("Laboratory Maniac", 304, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Laboratory Maniac", 359, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Laboratory Maniac", 71, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lantern Bearer", 72, Rarity.COMMON, mage.cards.l.LanternBearer.class)); - cards.add(new SetCardInfo("Lanterns' Lift", 72, Rarity.COMMON, mage.cards.l.LanternsLift.class)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 243, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Liesa, Forgotten Archangel", 433, Rarity.RARE, mage.cards.l.LiesaForgottenArchangel.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Axe", 162, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lightning Axe", 398, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Lightning Axe", 398, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Mauler", 163, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lightning Mauler", 399, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Lightning Mauler", 399, Rarity.UNCOMMON, mage.cards.l.LightningMauler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Liliana of the Veil", 475, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class, RETRO_ART)); cards.add(new SetCardInfo("Lingering Souls", 30, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); - cards.add(new SetCardInfo("Lord of Lineage", 327, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 461, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 98, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lumberknot", 206, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lumberknot", 414, Rarity.UNCOMMON, mage.cards.l.Lumberknot.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Luminous Phantom", 32, Rarity.COMMON, mage.cards.l.LuminousPhantom.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Luminous Phantom", 450, Rarity.COMMON, mage.cards.l.LuminousPhantom.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Lunarch Mantle", 31, Rarity.COMMON, mage.cards.l.LunarchMantle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lunarch Mantle", 344, Rarity.COMMON, mage.cards.l.LunarchMantle.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Lunarch Veteran", 32, Rarity.COMMON, mage.cards.l.LunarchVeteran.class, NON_FULL_USE_VARIOUS)); @@ -377,12 +327,8 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Mist Raven", 76, Rarity.UNCOMMON, mage.cards.m.MistRaven.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Moldgraf Millipede", 208, Rarity.COMMON, mage.cards.m.MoldgrafMillipede.class)); cards.add(new SetCardInfo("Moonlight Hunt", 209, Rarity.UNCOMMON, mage.cards.m.MoonlightHunt.class)); - cards.add(new SetCardInfo("Moonrise Intruder", 179, Rarity.COMMON, mage.cards.m.MoonriseIntruder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Moonrise Intruder", 466, Rarity.COMMON, mage.cards.m.MoonriseIntruder.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Moonscarred Werewolf", 212, Rarity.COMMON, mage.cards.m.MoonscarredWerewolf.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Moonscarred Werewolf", 468, Rarity.COMMON, mage.cards.m.MoonscarredWerewolf.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Morbid Opportunist", 124, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Morbid Opportunist", 388, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Morbid Opportunist", 388, Rarity.UNCOMMON, mage.cards.m.MorbidOpportunist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Morkrut Banshee", 125, Rarity.UNCOMMON, mage.cards.m.MorkrutBanshee.class)); cards.add(new SetCardInfo("Mountain", 294, Rarity.LAND, mage.cards.basiclands.Mountain.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 295, Rarity.LAND, mage.cards.basiclands.Mountain.class, RETRO_ART_USE_VARIOUS)); @@ -405,21 +351,14 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Olivia Voldaren", 246, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Olivia Voldaren", 490, Rarity.MYTHIC, mage.cards.o.OliviaVoldaren.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Olivia's Dragoon", 127, Rarity.COMMON, mage.cards.o.OliviasDragoon.class)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 287, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 474, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Overcharged Amalgam", 80, Rarity.RARE, mage.cards.o.OverchargedAmalgam.class)); cards.add(new SetCardInfo("Overgrown Farmland", 281, Rarity.RARE, mage.cards.o.OvergrownFarmland.class)); cards.add(new SetCardInfo("Pack Guardian", 211, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pack Guardian", 416, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Perfected Form", 454, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Perfected Form", 52, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 288, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Rally the Peasants", 347, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Rally the Peasants", 37, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 241, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 325, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 470, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Reckless Scholar", 81, Rarity.COMMON, mage.cards.r.RecklessScholar.class)); cards.add(new SetCardInfo("Reforge the Soul", 167, Rarity.RARE, mage.cards.r.ReforgeTheSoul.class)); cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS)); @@ -436,15 +375,12 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Savage Alliance", 169, Rarity.UNCOMMON, mage.cards.s.SavageAlliance.class)); cards.add(new SetCardInfo("Scorned Villager", 212, Rarity.COMMON, mage.cards.s.ScornedVillager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scorned Villager", 468, Rarity.COMMON, mage.cards.s.ScornedVillager.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Scrounged Scythe", 265, Rarity.COMMON, mage.cards.s.ScroungedScythe.class)); - cards.add(new SetCardInfo("Seasoned Cathar", 448, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Seasoned Cathar", 8, Rarity.UNCOMMON, mage.cards.s.SeasonedCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Second Harvest", 213, Rarity.RARE, mage.cards.s.SecondHarvest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Second Harvest", 417, Rarity.RARE, mage.cards.s.SecondHarvest.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Seize the Storm", 170, Rarity.COMMON, mage.cards.s.SeizeTheStorm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seize the Storm", 401, Rarity.COMMON, mage.cards.s.SeizeTheStorm.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Sever the Bloodline", 130, Rarity.UNCOMMON, mage.cards.s.SeverTheBloodline.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sever the Bloodline", 389, Rarity.UNCOMMON, mage.cards.s.SeverTheBloodline.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Sever the Bloodline", 389, Rarity.UNCOMMON, mage.cards.s.SeverTheBloodline.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Shattered Sanctum", 283, Rarity.RARE, mage.cards.s.ShatteredSanctum.class)); cards.add(new SetCardInfo("Shipwreck Marsh", 284, Rarity.RARE, mage.cards.s.ShipwreckMarsh.class)); cards.add(new SetCardInfo("Shrill Howler", 214, Rarity.UNCOMMON, mage.cards.s.ShrillHowler.class, NON_FULL_USE_VARIOUS)); @@ -500,7 +436,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Tamiyo, Field Researcher", 249, Rarity.MYTHIC, mage.cards.t.TamiyoFieldResearcher.class)); cards.add(new SetCardInfo("Temporal Mastery", 307, Rarity.MYTHIC, mage.cards.t.TemporalMastery.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temporal Mastery", 90, Rarity.MYTHIC, mage.cards.t.TemporalMastery.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Terror of Kruin Pass", 161, Rarity.RARE, mage.cards.t.TerrorOfKruinPass.class)); cards.add(new SetCardInfo("Thalia, Heretic Cathar", 300, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia, Heretic Cathar", 351, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia, Heretic Cathar", 44, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class, NON_FULL_USE_VARIOUS)); @@ -508,7 +443,7 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("The Gitrog Monster", 431, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Gitrog Monster", 489, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Meathook Massacre", 122, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Meathook Massacre", 387, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("The Meathook Massacre", 387, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Meathook Massacre", 486, Rarity.MYTHIC, mage.cards.t.TheMeathookMassacre.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Thermo-Alchemist", 174, Rarity.UNCOMMON, mage.cards.t.ThermoAlchemist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thermo-Alchemist", 403, Rarity.UNCOMMON, mage.cards.t.ThermoAlchemist.class, RETRO_ART_USE_VARIOUS)); @@ -521,7 +456,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Through the Breach", 175, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Through the Breach", 404, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Through the Breach", 487, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Timber Shredder", 203, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tireless Tracker", 318, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Torens, Fist of the Angels", 250, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class)); @@ -529,7 +463,7 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Town Gossipmonger", 451, Rarity.UNCOMMON, mage.cards.t.TownGossipmonger.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Town Gossipmonger", 46, Rarity.UNCOMMON, mage.cards.t.TownGossipmonger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tragic Slip", 134, Rarity.COMMON, mage.cards.t.TragicSlip.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tragic Slip", 390, Rarity.COMMON, mage.cards.t.TragicSlip.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Tragic Slip", 390, Rarity.COMMON, mage.cards.t.TragicSlip.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Travel Preparations", 220, Rarity.UNCOMMON, mage.cards.t.TravelPreparations.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Travel Preparations", 421, Rarity.UNCOMMON, mage.cards.t.TravelPreparations.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Traveler's Amulet", 273, Rarity.COMMON, mage.cards.t.TravelersAmulet.class)); @@ -537,11 +471,9 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Traverse the Ulvenwald", 422, Rarity.RARE, mage.cards.t.TraverseTheUlvenwald.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Tree of Perdition", 135, Rarity.RARE, mage.cards.t.TreeOfPerdition.class)); cards.add(new SetCardInfo("Triskaidekaphobia", 136, Rarity.UNCOMMON, mage.cards.t.Triskaidekaphobia.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Triskaidekaphobia", 391, Rarity.UNCOMMON, mage.cards.t.Triskaidekaphobia.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Triskaidekaphobia", 391, Rarity.UNCOMMON, mage.cards.t.Triskaidekaphobia.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Twinblade Geist", 452, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Twinblade Geist", 47, Rarity.UNCOMMON, mage.cards.t.TwinbladeGeist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Twinblade Invocation", 452, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Twinblade Invocation", 47, Rarity.UNCOMMON, mage.cards.t.TwinbladeInvocation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ulrich's Kindred", 176, Rarity.UNCOMMON, mage.cards.u.UlrichsKindred.class)); cards.add(new SetCardInfo("Ulvenwald Mysteries", 222, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ulvenwald Mysteries", 423, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class, RETRO_ART_USE_VARIOUS)); @@ -553,14 +485,12 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Vanquish the Horde", 49, Rarity.RARE, mage.cards.v.VanquishTheHorde.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vexing Devil", 178, Rarity.RARE, mage.cards.v.VexingDevil.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vexing Devil", 313, Rarity.RARE, mage.cards.v.VexingDevil.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Vildin-Pack Alpha", 156, Rarity.UNCOMMON, mage.cards.v.VildinPackAlpha.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Vildin-Pack Alpha", 464, Rarity.UNCOMMON, mage.cards.v.VildinPackAlpha.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Vilespawn Spider", 251, Rarity.UNCOMMON, mage.cards.v.VilespawnSpider.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vilespawn Spider", 436, Rarity.UNCOMMON, mage.cards.v.VilespawnSpider.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Village Messenger", 179, Rarity.COMMON, mage.cards.v.VillageMessenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Village Messenger", 466, Rarity.COMMON, mage.cards.v.VillageMessenger.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Village Rites", 137, Rarity.COMMON, mage.cards.v.VillageRites.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Village Rites", 392, Rarity.COMMON, mage.cards.v.VillageRites.class,RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Village Rites", 392, Rarity.COMMON, mage.cards.v.VillageRites.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Villagers of Estwald", 224, Rarity.COMMON, mage.cards.v.VillagersOfEstwald.class)); cards.add(new SetCardInfo("Voice of the Blessed", 50, Rarity.RARE, mage.cards.v.VoiceOfTheBlessed.class)); cards.add(new SetCardInfo("Voldaren Ambusher", 180, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class)); @@ -572,8 +502,6 @@ public class InnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Wandering Mind", 437, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Wedding Announcement", 453, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Wedding Announcement", 51, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wedding Festivity", 453, Rarity.RARE, mage.cards.w.WeddingFestivity.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Wedding Festivity", 51, Rarity.RARE, mage.cards.w.WeddingFestivity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 287, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 474, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Wild Hunger", 225, Rarity.UNCOMMON, mage.cards.w.WildHunger.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/Ixalan.java b/Mage.Sets/src/mage/sets/Ixalan.java index f8f7a904b35..00048cbae25 100644 --- a/Mage.Sets/src/mage/sets/Ixalan.java +++ b/Mage.Sets/src/mage/sets/Ixalan.java @@ -36,7 +36,6 @@ public final class Ixalan extends ExpansionSet { this.numBoosterDoubleFaced = -1; this.maxCardNumberInBooster = 279; - cards.add(new SetCardInfo("Adanto, the First Fort", 22, Rarity.RARE, mage.cards.a.AdantoTheFirstFort.class)); cards.add(new SetCardInfo("Adanto Vanguard", 1, Rarity.UNCOMMON, mage.cards.a.AdantoVanguard.class)); cards.add(new SetCardInfo("Admiral Beckett Brass", 217, Rarity.MYTHIC, mage.cards.a.AdmiralBeckettBrass.class)); cards.add(new SetCardInfo("Air Elemental", 45, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); @@ -48,7 +47,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Ashes of the Abhorrent", 2, Rarity.RARE, mage.cards.a.AshesOfTheAbhorrent.class)); cards.add(new SetCardInfo("Atzocan Archer", 176, Rarity.UNCOMMON, mage.cards.a.AtzocanArcher.class)); cards.add(new SetCardInfo("Axis of Mortality", 3, Rarity.MYTHIC, mage.cards.a.AxisOfMortality.class)); - cards.add(new SetCardInfo("Azcanta, the Sunken Ruin", 74, Rarity.RARE, mage.cards.a.AzcantaTheSunkenRuin.class)); cards.add(new SetCardInfo("Belligerent Brontodon", 218, Rarity.UNCOMMON, mage.cards.b.BelligerentBrontodon.class)); cards.add(new SetCardInfo("Bellowing Aegisaur", 4, Rarity.UNCOMMON, mage.cards.b.BellowingAegisaur.class)); cards.add(new SetCardInfo("Bishop of Rebirth", 5, Rarity.RARE, mage.cards.b.BishopOfRebirth.class)); @@ -74,7 +72,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Cobbled Wings", 233, Rarity.COMMON, mage.cards.c.CobbledWings.class)); cards.add(new SetCardInfo("Colossal Dreadmaw", 180, Rarity.COMMON, mage.cards.c.ColossalDreadmaw.class)); cards.add(new SetCardInfo("Commune with Dinosaurs", 181, Rarity.COMMON, mage.cards.c.CommuneWithDinosaurs.class)); - cards.add(new SetCardInfo("Conqueror's Foothold", 234, Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", 234, Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Contract Killing", 95, Rarity.COMMON, mage.cards.c.ContractKilling.class)); cards.add(new SetCardInfo("Costly Plunder", 96, Rarity.COMMON, mage.cards.c.CostlyPlunder.class)); @@ -158,7 +155,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Island", 265, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 266, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 267, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 191, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); cards.add(new SetCardInfo("Ixalan's Binding", 17, Rarity.UNCOMMON, mage.cards.i.IxalansBinding.class)); cards.add(new SetCardInfo("Ixalli's Diviner", 192, Rarity.COMMON, mage.cards.i.IxallisDiviner.class)); cards.add(new SetCardInfo("Ixalli's Keeper", 193, Rarity.COMMON, mage.cards.i.IxallisKeeper.class)); @@ -179,7 +175,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Lightning Strike", 149, Rarity.UNCOMMON, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Lookout's Dispersal", 62, Rarity.UNCOMMON, mage.cards.l.LookoutsDispersal.class)); cards.add(new SetCardInfo("Looming Altisaur", 23, Rarity.COMMON, mage.cards.l.LoomingAltisaur.class)); - cards.add(new SetCardInfo("Lost Vale", 235, Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Lurking Chupacabra", 111, Rarity.UNCOMMON, mage.cards.l.LurkingChupacabra.class)); cards.add(new SetCardInfo("Makeshift Munitions", 151, Rarity.UNCOMMON, mage.cards.m.MakeshiftMunitions.class)); cards.add(new SetCardInfo("Marauding Looter", 225, Rarity.UNCOMMON, mage.cards.m.MaraudingLooter.class)); @@ -212,7 +207,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Pounce", 200, Rarity.COMMON, mage.cards.p.Pounce.class)); cards.add(new SetCardInfo("Priest of the Wakening Sun", 27, Rarity.RARE, mage.cards.p.PriestOfTheWakeningSun.class)); cards.add(new SetCardInfo("Primal Amulet", 243, Rarity.RARE, mage.cards.p.PrimalAmulet.class)); - cards.add(new SetCardInfo("Primal Wellspring", 243, Rarity.RARE, mage.cards.p.PrimalWellspring.class)); cards.add(new SetCardInfo("Prosperous Pirates", 69, Rarity.COMMON, mage.cards.p.ProsperousPirates.class)); cards.add(new SetCardInfo("Prying Blade", 244, Rarity.COMMON, mage.cards.p.PryingBlade.class)); cards.add(new SetCardInfo("Pterodon Knight", 28, Rarity.COMMON, mage.cards.p.PterodonKnight.class)); @@ -275,8 +269,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Spell Pierce", 81, Rarity.COMMON, mage.cards.s.SpellPierce.class)); cards.add(new SetCardInfo("Spell Swindle", 82, Rarity.RARE, mage.cards.s.SpellSwindle.class)); cards.add(new SetCardInfo("Spike-Tailed Ceratops", 209, Rarity.COMMON, mage.cards.s.SpikeTailedCeratops.class)); - cards.add(new SetCardInfo("Spires of Orazca", 249, Rarity.RARE, mage.cards.s.SpiresOfOrazca.class)); - cards.add(new SetCardInfo("Spitfire Bastion", 173, Rarity.RARE, mage.cards.s.SpitfireBastion.class)); cards.add(new SetCardInfo("Spreading Rot", 125, Rarity.COMMON, mage.cards.s.SpreadingRot.class)); cards.add(new SetCardInfo("Star of Extinction", 161, Rarity.MYTHIC, mage.cards.s.StarOfExtinction.class)); cards.add(new SetCardInfo("Steadfast Armasaur", 39, Rarity.UNCOMMON, mage.cards.s.SteadfastArmasaur.class)); @@ -299,7 +291,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Swashbuckling", 167, Rarity.COMMON, mage.cards.s.Swashbuckling.class)); cards.add(new SetCardInfo("Sword-Point Diplomacy", 126, Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class)); cards.add(new SetCardInfo("Tempest Caller", 86, Rarity.UNCOMMON, mage.cards.t.TempestCaller.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 90, Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Territorial Hammerskull", 41, Rarity.COMMON, mage.cards.t.TerritorialHammerskull.class)); cards.add(new SetCardInfo("Thaumatic Compass", 249, Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); cards.add(new SetCardInfo("Thrash of Raptors", 168, Rarity.COMMON, mage.cards.t.ThrashOfRaptors.class)); @@ -309,7 +300,6 @@ public final class Ixalan extends ExpansionSet { cards.add(new SetCardInfo("Tishana's Wayfinder", 211, Rarity.COMMON, mage.cards.t.TishanasWayfinder.class)); cards.add(new SetCardInfo("Tishana, Voice of Thunder", 230, Rarity.MYTHIC, mage.cards.t.TishanaVoiceOfThunder.class)); cards.add(new SetCardInfo("Tocatli Honor Guard", 42, Rarity.RARE, mage.cards.t.TocatliHonorGuard.class)); - cards.add(new SetCardInfo("Treasure Cove", 250, Rarity.RARE, mage.cards.t.TreasureCove.class)); cards.add(new SetCardInfo("Treasure Map", 250, Rarity.RARE, mage.cards.t.TreasureMap.class)); cards.add(new SetCardInfo("Trove of Temptation", 171, Rarity.UNCOMMON, mage.cards.t.TroveOfTemptation.class)); cards.add(new SetCardInfo("Unclaimed Territory", 258, Rarity.UNCOMMON, mage.cards.u.UnclaimedTerritory.class)); diff --git a/Mage.Sets/src/mage/sets/IxalanPromos.java b/Mage.Sets/src/mage/sets/IxalanPromos.java index d472b0c1307..7f08fba3205 100644 --- a/Mage.Sets/src/mage/sets/IxalanPromos.java +++ b/Mage.Sets/src/mage/sets/IxalanPromos.java @@ -20,7 +20,6 @@ public class IxalanPromos extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Adanto, the First Fort", "22s", Rarity.RARE, mage.cards.a.AdantoTheFirstFort.class)); cards.add(new SetCardInfo("Admiral Beckett Brass", "217s", Rarity.MYTHIC, mage.cards.a.AdmiralBeckettBrass.class)); cards.add(new SetCardInfo("Angrath's Marauders", "132s", Rarity.RARE, mage.cards.a.AngrathsMarauders.class)); cards.add(new SetCardInfo("Arcane Adaptation", "46p", Rarity.RARE, mage.cards.a.ArcaneAdaptation.class, NON_FULL_USE_VARIOUS)); @@ -29,7 +28,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Ashes of the Abhorrent", "2p", Rarity.RARE, mage.cards.a.AshesOfTheAbhorrent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashes of the Abhorrent", "2s", Rarity.RARE, mage.cards.a.AshesOfTheAbhorrent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Axis of Mortality", "3s", Rarity.MYTHIC, mage.cards.a.AxisOfMortality.class)); - cards.add(new SetCardInfo("Azcanta, the Sunken Ruin", "74s", Rarity.RARE, mage.cards.a.AzcantaTheSunkenRuin.class)); cards.add(new SetCardInfo("Bishop of Rebirth", 5, Rarity.RARE, mage.cards.b.BishopOfRebirth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bishop of Rebirth", "5s", Rarity.RARE, mage.cards.b.BishopOfRebirth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodcrazed Paladin", "93s", Rarity.RARE, mage.cards.b.BloodcrazedPaladin.class)); @@ -42,7 +40,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Captivating Crew", "137s", Rarity.RARE, mage.cards.c.CaptivatingCrew.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carnage Tyrant", "179p", Rarity.MYTHIC, mage.cards.c.CarnageTyrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carnage Tyrant", "179s", Rarity.MYTHIC, mage.cards.c.CarnageTyrant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Conqueror's Foothold", "234s", Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", "234s", Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Daring Saboteur", "49s", Rarity.RARE, mage.cards.d.DaringSaboteur.class)); cards.add(new SetCardInfo("Deadeye Tracker", "99p", Rarity.RARE, mage.cards.d.DeadeyeTracker.class, NON_FULL_USE_VARIOUS)); @@ -75,21 +72,18 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Herald of Secret Streams", "59s", Rarity.RARE, mage.cards.h.HeraldOfSecretStreams.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hostage Taker", "223s", Rarity.RARE, mage.cards.h.HostageTaker.class)); cards.add(new SetCardInfo("Huatli, Warrior Poet", "224s", Rarity.MYTHIC, mage.cards.h.HuatliWarriorPoet.class)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", "191s", Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); cards.add(new SetCardInfo("Jace, Cunning Castaway", "60s", Rarity.MYTHIC, mage.cards.j.JaceCunningCastaway.class)); cards.add(new SetCardInfo("Kinjalli's Sunwing", "19p", Rarity.RARE, mage.cards.k.KinjallisSunwing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kinjalli's Sunwing", "19s", Rarity.RARE, mage.cards.k.KinjallisSunwing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kopala, Warden of Waves", "61p", Rarity.RARE, mage.cards.k.KopalaWardenOfWaves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kopala, Warden of Waves", "61s", Rarity.RARE, mage.cards.k.KopalaWardenOfWaves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Legion's Landing", "22s", Rarity.RARE, mage.cards.l.LegionsLanding.class)); - cards.add(new SetCardInfo("Lost Vale", "235s", Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Mavren Fein, Dusk Apostle", "24p", Rarity.RARE, mage.cards.m.MavrenFeinDuskApostle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mavren Fein, Dusk Apostle", "24s", Rarity.RARE, mage.cards.m.MavrenFeinDuskApostle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Old-Growth Dryads", "199s", Rarity.RARE, mage.cards.o.OldGrowthDryads.class)); cards.add(new SetCardInfo("Overflowing Insight", "66s", Rarity.MYTHIC, mage.cards.o.OverflowingInsight.class)); cards.add(new SetCardInfo("Priest of the Wakening Sun", "27s", Rarity.RARE, mage.cards.p.PriestOfTheWakeningSun.class)); cards.add(new SetCardInfo("Primal Amulet", "243s", Rarity.RARE, mage.cards.p.PrimalAmulet.class)); - cards.add(new SetCardInfo("Primal Wellspring", "243s", Rarity.RARE, mage.cards.p.PrimalWellspring.class)); cards.add(new SetCardInfo("Rampaging Ferocidon", "154s", Rarity.RARE, mage.cards.r.RampagingFerocidon.class)); cards.add(new SetCardInfo("Regisaur Alpha", "227p", Rarity.RARE, mage.cards.r.RegisaurAlpha.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Regisaur Alpha", "227s", Rarity.RARE, mage.cards.r.RegisaurAlpha.class, NON_FULL_USE_VARIOUS)); @@ -118,8 +112,6 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Sorcerous Spyglass", "248s", Rarity.RARE, mage.cards.s.SorcerousSpyglass.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spell Swindle", "82p", Rarity.RARE, mage.cards.s.SpellSwindle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spell Swindle", "82s", Rarity.RARE, mage.cards.s.SpellSwindle.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Spires of Orazca", "249s", Rarity.RARE, mage.cards.s.SpiresOfOrazca.class)); - cards.add(new SetCardInfo("Spitfire Bastion", "173s", Rarity.RARE, mage.cards.s.SpitfireBastion.class)); cards.add(new SetCardInfo("Star of Extinction", "161p", Rarity.MYTHIC, mage.cards.s.StarOfExtinction.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Star of Extinction", "161s", Rarity.MYTHIC, mage.cards.s.StarOfExtinction.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sunbird's Invocation", "165p", Rarity.RARE, mage.cards.s.SunbirdsInvocation.class, NON_FULL_USE_VARIOUS)); @@ -128,13 +120,11 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Sunpetal Grove", "257s", Rarity.RARE, mage.cards.s.SunpetalGrove.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sword-Point Diplomacy", "126p", Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sword-Point Diplomacy", "126s", Rarity.RARE, mage.cards.s.SwordPointDiplomacy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Aclazotz", "90s", Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Thaumatic Compass", "249s", Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); cards.add(new SetCardInfo("Tilonalli's Skinshifter", "170s", Rarity.RARE, mage.cards.t.TilonallisSkinshifter.class)); cards.add(new SetCardInfo("Tishana, Voice of Thunder", "230s", Rarity.MYTHIC, mage.cards.t.TishanaVoiceOfThunder.class)); cards.add(new SetCardInfo("Tocatli Honor Guard", "42p", Rarity.RARE, mage.cards.t.TocatliHonorGuard.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tocatli Honor Guard", "42s", Rarity.RARE, mage.cards.t.TocatliHonorGuard.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Treasure Cove", "250s", Rarity.RARE, mage.cards.t.TreasureCove.class)); cards.add(new SetCardInfo("Treasure Map", "250s", Rarity.RARE, mage.cards.t.TreasureMap.class)); cards.add(new SetCardInfo("Unclaimed Territory", 258, Rarity.UNCOMMON, mage.cards.u.UnclaimedTerritory.class)); cards.add(new SetCardInfo("Vance's Blasting Cannons", "173s", Rarity.RARE, mage.cards.v.VancesBlastingCannons.class)); @@ -150,5 +140,5 @@ public class IxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Wakening Sun's Avatar", "44s", Rarity.MYTHIC, mage.cards.w.WakeningSunsAvatar.class)); cards.add(new SetCardInfo("Waker of the Wilds", "215s", Rarity.RARE, mage.cards.w.WakerOfTheWilds.class)); cards.add(new SetCardInfo("Walk the Plank", 130, Rarity.UNCOMMON, mage.cards.w.WalkThePlank.class)); - } + } } diff --git a/Mage.Sets/src/mage/sets/JudgeGiftCards2021.java b/Mage.Sets/src/mage/sets/JudgeGiftCards2021.java index efe4cd6675d..701106b1162 100644 --- a/Mage.Sets/src/mage/sets/JudgeGiftCards2021.java +++ b/Mage.Sets/src/mage/sets/JudgeGiftCards2021.java @@ -27,7 +27,6 @@ public class JudgeGiftCards2021 extends ExpansionSet { cards.add(new SetCardInfo("K'rrik, Son of Yawgmoth", 2, Rarity.RARE, mage.cards.k.KrrikSonOfYawgmoth.class)); cards.add(new SetCardInfo("Mizzix of the Izmagnus", 8, Rarity.MYTHIC, mage.cards.m.MizzixOfTheIzmagnus.class)); cards.add(new SetCardInfo("Morophon, the Boundless", 1, Rarity.MYTHIC, mage.cards.m.MorophonTheBoundless.class)); - cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 9, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 9, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class)); cards.add(new SetCardInfo("The Gitrog Monster", 5, Rarity.MYTHIC, mage.cards.t.TheGitrogMonster.class)); cards.add(new SetCardInfo("Zacama, Primal Calamity", 10, Rarity.MYTHIC, mage.cards.z.ZacamaPrimalCalamity.class)); diff --git a/Mage.Sets/src/mage/sets/JudgeGiftCards2022.java b/Mage.Sets/src/mage/sets/JudgeGiftCards2022.java index 9ac65f709f6..d17992860c3 100644 --- a/Mage.Sets/src/mage/sets/JudgeGiftCards2022.java +++ b/Mage.Sets/src/mage/sets/JudgeGiftCards2022.java @@ -23,7 +23,6 @@ public class JudgeGiftCards2022 extends ExpansionSet { cards.add(new SetCardInfo("Animate Dead", 7, Rarity.RARE, mage.cards.a.AnimateDead.class, RETRO_ART)); cards.add(new SetCardInfo("Greater Auramancy", 1, Rarity.RARE, mage.cards.g.GreaterAuramancy.class)); cards.add(new SetCardInfo("Growing Rites of Itlimoc", 10, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 10, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); cards.add(new SetCardInfo("No Mercy", 9, Rarity.RARE, mage.cards.n.NoMercy.class)); cards.add(new SetCardInfo("Omniscience", 2, Rarity.RARE, mage.cards.o.Omniscience.class)); cards.add(new SetCardInfo("Parallel Lives", 3, Rarity.RARE, mage.cards.p.ParallelLives.class)); diff --git a/Mage.Sets/src/mage/sets/JumpstartHistoricHorizons.java b/Mage.Sets/src/mage/sets/JumpstartHistoricHorizons.java index b2c2b9b6e99..08b6d104555 100644 --- a/Mage.Sets/src/mage/sets/JumpstartHistoricHorizons.java +++ b/Mage.Sets/src/mage/sets/JumpstartHistoricHorizons.java @@ -170,7 +170,6 @@ public final class JumpstartHistoricHorizons extends ExpansionSet { cards.add(new SetCardInfo("Haunted Dead", 336, Rarity.UNCOMMON, mage.cards.h.HauntedDead.class)); cards.add(new SetCardInfo("Healer's Flock", 91, Rarity.UNCOMMON, mage.cards.h.HealersFlock.class)); cards.add(new SetCardInfo("Heir of Falkenrath", 338, Rarity.UNCOMMON, mage.cards.h.HeirOfFalkenrath.class)); - cards.add(new SetCardInfo("Heir to the Night", 338, Rarity.UNCOMMON, mage.cards.h.HeirToTheNight.class)); cards.add(new SetCardInfo("Hell Mongrel", 339, Rarity.COMMON, mage.cards.h.HellMongrel.class)); cards.add(new SetCardInfo("Herd Baloth", 584, Rarity.UNCOMMON, mage.cards.h.HerdBaloth.class)); cards.add(new SetCardInfo("Hive Stirrings", 94, Rarity.COMMON, mage.cards.h.HiveStirrings.class)); @@ -378,7 +377,6 @@ public final class JumpstartHistoricHorizons extends ExpansionSet { cards.add(new SetCardInfo("Warteye Witch", 404, Rarity.COMMON, mage.cards.w.WarteyeWitch.class)); cards.add(new SetCardInfo("Wavesifter", 726, Rarity.COMMON, mage.cards.w.Wavesifter.class)); cards.add(new SetCardInfo("Webweaver Changeling", 666, Rarity.UNCOMMON, mage.cards.w.WebweaverChangeling.class)); - cards.add(new SetCardInfo("Westvale Cult Leader", 90, Rarity.RARE, mage.cards.w.WestvaleCultLeader.class)); cards.add(new SetCardInfo("Windcaller Aven", 275, Rarity.COMMON, mage.cards.w.WindcallerAven.class)); cards.add(new SetCardInfo("Winding Way", 670, Rarity.COMMON, mage.cards.w.WindingWay.class)); cards.add(new SetCardInfo("Winged Shepherd", 158, Rarity.COMMON, mage.cards.w.WingedShepherd.class)); diff --git a/Mage.Sets/src/mage/sets/JurassicWorldCollection.java b/Mage.Sets/src/mage/sets/JurassicWorldCollection.java index 899e568fce2..d22ade219c3 100644 --- a/Mage.Sets/src/mage/sets/JurassicWorldCollection.java +++ b/Mage.Sets/src/mage/sets/JurassicWorldCollection.java @@ -50,7 +50,6 @@ public final class JurassicWorldCollection extends ExpansionSet { cards.add(new SetCardInfo("Indoraptor, the Perfect Hybrid", 40, Rarity.RARE, mage.cards.i.IndoraptorThePerfectHybrid.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 22, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", "22b", Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Jurassic Park", 7, Rarity.RARE, mage.cards.j.JurassicPark.class)); cards.add(new SetCardInfo("Life Finds a Way", 31, Rarity.RARE, mage.cards.l.LifeFindsAWay.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Life Finds a Way", 5, Rarity.RARE, mage.cards.l.LifeFindsAWay.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 24, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index 35596662e26..81e349639fa 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -48,13 +48,9 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Asari Captain", 327, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class, NON_FULL_USE_VARIOUS)); @@ -88,7 +84,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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", 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)); @@ -119,18 +114,12 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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("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, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Eiganjo Exemplar", 309, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class, NON_FULL_USE_VARIOUS)); @@ -145,7 +134,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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)); @@ -168,7 +156,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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_UST_VARIOUS)); cards.add(new SetCardInfo("Forest", 302, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_UST_VARIOUS)); - cards.add(new SetCardInfo("Fragment of Konda", 12, Rarity.UNCOMMON, mage.cards.f.FragmentOfKonda.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)); @@ -193,7 +180,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Greater Tanuki", 189, Rarity.COMMON, mage.cards.g.GreaterTanuki.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("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)); @@ -215,7 +201,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, NON_FULL_USE_VARIOUS)); @@ -287,9 +272,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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, 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)); @@ -312,13 +294,9 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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)); @@ -344,7 +322,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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)); @@ -371,7 +348,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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)); @@ -383,13 +359,9 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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)); @@ -409,7 +381,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Plains", 293, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_UST_VARIOUS)); cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_UST_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", 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)); @@ -423,16 +394,10 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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)); @@ -465,7 +430,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Seismic Wave", 161, Rarity.UNCOMMON, mage.cards.s.SeismicWave.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", 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)); @@ -577,12 +541,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet { 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, 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)); diff --git a/Mage.Sets/src/mage/sets/LorwynEclipsed.java b/Mage.Sets/src/mage/sets/LorwynEclipsed.java index 8d0ca69aa6e..80497f7960e 100644 --- a/Mage.Sets/src/mage/sets/LorwynEclipsed.java +++ b/Mage.Sets/src/mage/sets/LorwynEclipsed.java @@ -22,13 +22,17 @@ public final class LorwynEclipsed extends ExpansionSet { cards.add(new SetCardInfo("Ashling's Command", 205, Rarity.RARE, mage.cards.a.AshlingsCommand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashling's Command", 330, Rarity.RARE, mage.cards.a.AshlingsCommand.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ashling, Rekindled", 124, Rarity.RARE, mage.cards.a.AshlingRekindled.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ashling, Rekindled", 290, Rarity.RARE, mage.cards.a.AshlingRekindled.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bitterbloom Bearer", 310, Rarity.MYTHIC, mage.cards.b.BitterbloomBearer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bitterbloom Bearer", 352, Rarity.MYTHIC, mage.cards.b.BitterbloomBearer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bitterbloom Bearer", 88, Rarity.MYTHIC, mage.cards.b.BitterbloomBearer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blood Crypt", "349b", Rarity.RARE, mage.cards.b.BloodCrypt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Crypt", 262, Rarity.RARE, mage.cards.b.BloodCrypt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Blood Crypt", 349, Rarity.RARE, mage.cards.b.BloodCrypt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deceit", 212, Rarity.MYTHIC, mage.cards.d.Deceit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deceit", 293, Rarity.MYTHIC, mage.cards.d.Deceit.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dose of Dawnglow", 100, Rarity.UNCOMMON, mage.cards.d.DoseOfDawnglow.class)); cards.add(new SetCardInfo("Eirdu, Carrier of Dawn", 13, Rarity.MYTHIC, mage.cards.e.EirduCarrierOfDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Eirdu, Carrier of Dawn", 286, Rarity.MYTHIC, mage.cards.e.EirduCarrierOfDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Emptiness", 222, Rarity.MYTHIC, mage.cards.e.Emptiness.class, NON_FULL_USE_VARIOUS)); @@ -37,23 +41,29 @@ public final class LorwynEclipsed extends ExpansionSet { cards.add(new SetCardInfo("Figure of Fable", 372, Rarity.RARE, mage.cards.f.FigureOfFable.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Formidable Speaker", 176, Rarity.RARE, mage.cards.f.FormidableSpeaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Formidable Speaker", 366, Rarity.RARE, mage.cards.f.FormidableSpeaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hallowed Fountain", "347b", Rarity.RARE, mage.cards.h.HallowedFountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Fountain", 265, Rarity.RARE, mage.cards.h.HallowedFountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Fountain", 347, Rarity.RARE, mage.cards.h.HallowedFountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Isilu, Carrier of Twilight", 13, Rarity.MYTHIC, mage.cards.i.IsiluCarrierOfTwilight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Isilu, Carrier of Twilight", 286, Rarity.MYTHIC, mage.cards.i.IsiluCarrierOfTwilight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("High Perfect Morcant", 229, Rarity.RARE, mage.cards.h.HighPerfectMorcant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("High Perfect Morcant", 373, Rarity.RARE, mage.cards.h.HighPerfectMorcant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kirol, Attentive First-Year", 231, Rarity.RARE, mage.cards.k.KirolAttentiveFirstYear.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kirol, Attentive First-Year", 374, Rarity.RARE, mage.cards.k.KirolAttentiveFirstYear.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morningtide's Light", 27, Rarity.MYTHIC, mage.cards.m.MorningtidesLight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Morningtide's Light", 301, Rarity.MYTHIC, mage.cards.m.MorningtidesLight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mutable Explorer", 186, Rarity.RARE, mage.cards.m.MutableExplorer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mutable Explorer", 327, Rarity.RARE, mage.cards.m.MutableExplorer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Overgrown Tomb", "350b", Rarity.RARE, mage.cards.o.OvergrownTomb.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overgrown Tomb", 266, Rarity.RARE, mage.cards.o.OvergrownTomb.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overgrown Tomb", 350, Rarity.RARE, mage.cards.o.OvergrownTomb.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Perfect Intimidation", 115, Rarity.UNCOMMON, mage.cards.p.PerfectIntimidation.class)); + cards.add(new SetCardInfo("Steam Vents", "348b", Rarity.RARE, mage.cards.s.SteamVents.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Steam Vents", 267, Rarity.RARE, mage.cards.s.SteamVents.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Steam Vents", 348, Rarity.RARE, mage.cards.s.SteamVents.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sygg, Wanderbrine Shield", 288, Rarity.RARE, mage.cards.s.SyggWanderbrineShield.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sygg, Wanderbrine Shield", 76, Rarity.RARE, mage.cards.s.SyggWanderbrineShield.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sygg, Wanderwine Wisdom", 288, Rarity.RARE, mage.cards.s.SyggWanderwineWisdom.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sygg, Wanderwine Wisdom", 76, Rarity.RARE, mage.cards.s.SyggWanderwineWisdom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Temple Garden", "351b", Rarity.RARE, mage.cards.t.TempleGarden.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple Garden", 268, Rarity.RARE, mage.cards.t.TempleGarden.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temple Garden", 351, Rarity.RARE, mage.cards.t.TempleGarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unexpected Assistance", 80, Rarity.COMMON, mage.cards.u.UnexpectedAssistance.class)); } } diff --git a/Mage.Sets/src/mage/sets/MagicOnlinePromos.java b/Mage.Sets/src/mage/sets/MagicOnlinePromos.java index bcb19295bb5..a9be1013abe 100644 --- a/Mage.Sets/src/mage/sets/MagicOnlinePromos.java +++ b/Mage.Sets/src/mage/sets/MagicOnlinePromos.java @@ -4,9 +4,6 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * https://scryfall.com/sets/prm */ @@ -103,7 +100,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Angel of Suffering", 99767, Rarity.MYTHIC, mage.cards.a.AngelOfSuffering.class)); cards.add(new SetCardInfo("Angel of the Ruins", 90002, Rarity.RARE, mage.cards.a.AngelOfTheRuins.class)); cards.add(new SetCardInfo("Angelfire Ignition", 94080, Rarity.RARE, mage.cards.a.AngelfireIgnition.class)); - cards.add(new SetCardInfo("Angelic Enforcer", 93888, Rarity.MYTHIC, mage.cards.a.AngelicEnforcer.class)); cards.add(new SetCardInfo("Angelic Sleuth", 99921, Rarity.RARE, mage.cards.a.AngelicSleuth.class)); cards.add(new SetCardInfo("Anger of the Gods", 102265, Rarity.RARE, mage.cards.a.AngerOfTheGods.class)); cards.add(new SetCardInfo("Angrath, Captain of Chaos", 72237, Rarity.UNCOMMON, mage.cards.a.AngrathCaptainOfChaos.class, NON_FULL_USE_VARIOUS)); @@ -139,12 +135,10 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Arcbound Ravager", 72888, Rarity.RARE, mage.cards.a.ArcboundRavager.class)); cards.add(new SetCardInfo("Archaeomancer's Map", 90008, Rarity.RARE, mage.cards.a.ArchaeomancersMap.class)); cards.add(new SetCardInfo("Archangel of Wrath", 103392, Rarity.RARE, mage.cards.a.ArchangelOfWrath.class)); - cards.add(new SetCardInfo("Archdemon of Greed", 43503, Rarity.RARE, mage.cards.a.ArchdemonOfGreed.class)); cards.add(new SetCardInfo("Archelos, Lagoon Mystic", 86334, Rarity.RARE, mage.cards.a.ArchelosLagoonMystic.class)); cards.add(new SetCardInfo("Archfiend of Depravity", 55711, Rarity.RARE, mage.cards.a.ArchfiendOfDepravity.class)); cards.add(new SetCardInfo("Archfiend of Ifnir", 64422, Rarity.RARE, mage.cards.a.ArchfiendOfIfnir.class)); cards.add(new SetCardInfo("Archipelagore", 81005, Rarity.UNCOMMON, mage.cards.a.Archipelagore.class)); - cards.add(new SetCardInfo("Architect of Restoration", 97897, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class)); cards.add(new SetCardInfo("Archmage Emeritus", 90016, Rarity.RARE, mage.cards.a.ArchmageEmeritus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archmage Emeritus", 90018, Rarity.RARE, mage.cards.a.ArchmageEmeritus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archmage's Charm", 91233, Rarity.RARE, mage.cards.a.ArchmagesCharm.class, RETRO_ART)); @@ -159,7 +153,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Argivian Archaeologist", 219, Rarity.RARE, mage.cards.a.ArgivianArchaeologist.class, RETRO_ART)); cards.add(new SetCardInfo("Argothian Enchantress", 36104, Rarity.RARE, mage.cards.a.ArgothianEnchantress.class, RETRO_ART)); cards.add(new SetCardInfo("Arid Mesa", 91405, Rarity.RARE, mage.cards.a.AridMesa.class)); - cards.add(new SetCardInfo("Arlinn, the Moon's Fury", 94060, Rarity.MYTHIC, mage.cards.a.ArlinnTheMoonsFury.class)); cards.add(new SetCardInfo("Arlinn, the Pack's Hope", 94060, Rarity.MYTHIC, mage.cards.a.ArlinnThePacksHope.class)); cards.add(new SetCardInfo("Arlinn, Voice of the Pack", 72239, Rarity.UNCOMMON, mage.cards.a.ArlinnVoiceOfThePack.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arlinn, Voice of the Pack", 77973, Rarity.UNCOMMON, mage.cards.a.ArlinnVoiceOfThePack.class, NON_FULL_USE_VARIOUS)); @@ -180,7 +173,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Ashiok, Dream Render", 72259, Rarity.UNCOMMON, mage.cards.a.AshiokDreamRender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashiok, Dream Render", 77993, Rarity.UNCOMMON, mage.cards.a.AshiokDreamRender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashiok, Nightmare Muse", 79847, Rarity.MYTHIC, mage.cards.a.AshiokNightmareMuse.class)); - cards.add(new SetCardInfo("Ashmouth Dragon", 94012, Rarity.RARE, mage.cards.a.AshmouthDragon.class)); cards.add(new SetCardInfo("Ashnod the Uncaring", 105806, Rarity.MYTHIC, mage.cards.a.AshnodTheUncaring.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ashnod the Uncaring", 105808, Rarity.MYTHIC, mage.cards.a.AshnodTheUncaring.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ashnod, Flesh Mechanist", 105688, Rarity.RARE, mage.cards.a.AshnodFleshMechanist.class)); @@ -254,7 +246,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Beledros Witherbloom", 90318, Rarity.MYTHIC, mage.cards.b.BeledrosWitherbloom.class)); cards.add(new SetCardInfo("Bell Borca, Spectral Sergeant", 86308, Rarity.RARE, mage.cards.b.BellBorcaSpectralSergeant.class)); cards.add(new SetCardInfo("Bellowing Mauler", 99853, Rarity.RARE, mage.cards.b.BellowingMauler.class)); - cards.add(new SetCardInfo("Benevolent Geist", 93950, Rarity.RARE, mage.cards.b.BenevolentGeist.class)); cards.add(new SetCardInfo("Bennie Bracks, Zoologist", 99815, Rarity.MYTHIC, mage.cards.b.BennieBracksZoologist.class)); cards.add(new SetCardInfo("Bident of Thassa", 50114, Rarity.RARE, mage.cards.b.BidentOfThassa.class)); cards.add(new SetCardInfo("Bile Blight", 53838, Rarity.UNCOMMON, mage.cards.b.BileBlight.class)); @@ -539,7 +530,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Crash the Party", 99839, Rarity.RARE, mage.cards.c.CrashTheParty.class)); cards.add(new SetCardInfo("Crawling Barrens", 83732, Rarity.RARE, mage.cards.c.CrawlingBarrens.class)); cards.add(new SetCardInfo("Creative Technique", 90122, Rarity.RARE, mage.cards.c.CreativeTechnique.class)); - cards.add(new SetCardInfo("Creeping Inn", 94088, Rarity.MYTHIC, mage.cards.c.CreepingInn.class)); cards.add(new SetCardInfo("Creeping Mold", 32525, Rarity.UNCOMMON, mage.cards.c.CreepingMold.class, RETRO_ART)); cards.add(new SetCardInfo("Creepy Puppeteer", 95365, Rarity.RARE, mage.cards.c.CreepyPuppeteer.class)); cards.add(new SetCardInfo("Crippling Fear", 88286, Rarity.RARE, mage.cards.c.CripplingFear.class)); @@ -669,7 +659,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Dimir Guildmage", 32579, Rarity.UNCOMMON, mage.cards.d.DimirGuildmage.class)); cards.add(new SetCardInfo("Dimir Signet", 46924, Rarity.UNCOMMON, mage.cards.d.DimirSignet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dimir Signet", 62435, Rarity.COMMON, mage.cards.d.DimirSignet.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire-Strain Anarchist", 95397, Rarity.MYTHIC, mage.cards.d.DireStrainAnarchist.class)); cards.add(new SetCardInfo("Dire-Strain Rampage", 94070, Rarity.RARE, mage.cards.d.DireStrainRampage.class)); cards.add(new SetCardInfo("Diregraf Ghoul", 42882, Rarity.UNCOMMON, mage.cards.d.DiregrafGhoul.class)); cards.add(new SetCardInfo("Dirge Bat", 80935, Rarity.RARE, mage.cards.d.DirgeBat.class, NON_FULL_USE_VARIOUS)); @@ -714,7 +703,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Dragon Broodmother", 32553, Rarity.MYTHIC, mage.cards.d.DragonBroodmother.class)); cards.add(new SetCardInfo("Dragon Fodder", 55898, Rarity.COMMON, mage.cards.d.DragonFodder.class)); cards.add(new SetCardInfo("Dragon Throne of Tarkir", 54565, Rarity.RARE, mage.cards.d.DragonThroneOfTarkir.class)); - cards.add(new SetCardInfo("Dragon-Kami's Egg", 98051, Rarity.RARE, mage.cards.d.DragonKamisEgg.class)); cards.add(new SetCardInfo("Dragonkin Berserker", 88310, Rarity.RARE, mage.cards.d.DragonkinBerserker.class)); cards.add(new SetCardInfo("Dragonlord Dromoka", 102319, Rarity.MYTHIC, mage.cards.d.DragonlordDromoka.class)); cards.add(new SetCardInfo("Dragonlord's Servant", 55884, Rarity.UNCOMMON, mage.cards.d.DragonlordsServant.class)); @@ -760,7 +748,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Eater of Hope", 51918, Rarity.RARE, mage.cards.e.EaterOfHope.class)); cards.add(new SetCardInfo("Eater of Virtue", 98111, Rarity.RARE, mage.cards.e.EaterOfVirtue.class)); cards.add(new SetCardInfo("Ebondeath, Dracolich", 92692, Rarity.MYTHIC, mage.cards.e.EbondeathDracolich.class)); - cards.add(new SetCardInfo("Echo of Death's Wail", 97969, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class)); cards.add(new SetCardInfo("Echo of Eons", 95469, Rarity.RARE, mage.cards.e.EchoOfEons.class)); cards.add(new SetCardInfo("Ecological Appreciation", 90166, Rarity.MYTHIC, mage.cards.e.EcologicalAppreciation.class)); cards.add(new SetCardInfo("Eerie Ultimatum", 80895, Rarity.RARE, mage.cards.e.EerieUltimatum.class)); @@ -972,7 +959,7 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Forest", 40050, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 40060, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 40094, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 53875, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS )); + cards.add(new SetCardInfo("Forest", 53875, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Forest", 58261, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 73628, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 81872, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); @@ -1045,7 +1032,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Getaway Car", 99727, Rarity.RARE, mage.cards.g.GetawayCar.class)); cards.add(new SetCardInfo("Geyadrone Dihada", 91329, Rarity.MYTHIC, mage.cards.g.GeyadroneDihada.class)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", 66896, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); - cards.add(new SetCardInfo("Ghastly Mimicry", 95313, Rarity.RARE, mage.cards.g.GhastlyMimicry.class)); cards.add(new SetCardInfo("Ghen, Arcanum Weaver", 86340, Rarity.RARE, mage.cards.g.GhenArcanumWeaver.class)); cards.add(new SetCardInfo("Ghor-Clan Rampager", 50110, Rarity.UNCOMMON, mage.cards.g.GhorClanRampager.class)); cards.add(new SetCardInfo("Ghost of Ramirez DePietro", 86286, Rarity.UNCOMMON, mage.cards.g.GhostOfRamirezDePietro.class)); @@ -1233,7 +1219,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Hoard Hauler", 99747, Rarity.RARE, mage.cards.h.HoardHauler.class)); cards.add(new SetCardInfo("Hobgoblin Bandit Lord", 92734, Rarity.RARE, mage.cards.h.HobgoblinBanditLord.class)); cards.add(new SetCardInfo("Hofri Ghostforge", 90278, Rarity.MYTHIC, mage.cards.h.HofriGhostforge.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 95433, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Hollowhenge Overlord", 95419, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class)); cards.add(new SetCardInfo("Honor of the Pure", 43554, Rarity.RARE, mage.cards.h.HonorOfThePure.class)); cards.add(new SetCardInfo("Honored Hierarch", 57598, Rarity.RARE, mage.cards.h.HonoredHierarch.class)); @@ -1246,8 +1231,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Hostile Hostel", 94088, Rarity.MYTHIC, mage.cards.h.HostileHostel.class)); cards.add(new SetCardInfo("Hostile Negotiations", 105712, Rarity.RARE, mage.cards.h.HostileNegotiations.class)); cards.add(new SetCardInfo("Howling Moon", 95417, Rarity.RARE, mage.cards.h.HowlingMoon.class)); - cards.add(new SetCardInfo("Howlpack Alpha", 42866, Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); - cards.add(new SetCardInfo("Howlpack Avenger", 95389, Rarity.RARE, mage.cards.h.HowlpackAvenger.class)); cards.add(new SetCardInfo("Howlpack Piper", 95425, Rarity.RARE, mage.cards.h.HowlpackPiper.class)); cards.add(new SetCardInfo("Huatli, the Sun's Heart", 72241, Rarity.UNCOMMON, mage.cards.h.HuatliTheSunsHeart.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Huatli, the Sun's Heart", 77975, Rarity.UNCOMMON, mage.cards.h.HuatliTheSunsHeart.class, NON_FULL_USE_VARIOUS)); @@ -1320,7 +1303,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Inscription of Abundance", 83728, Rarity.RARE, mage.cards.i.InscriptionOfAbundance.class)); cards.add(new SetCardInfo("Inscription of Insight", 83802, Rarity.RARE, mage.cards.i.InscriptionOfInsight.class)); cards.add(new SetCardInfo("Inscription of Ruin", 83798, Rarity.RARE, mage.cards.i.InscriptionOfRuin.class)); - cards.add(new SetCardInfo("Insidious Mist", 60472, Rarity.RARE, mage.cards.i.InsidiousMist.class)); cards.add(new SetCardInfo("Inspired Idea", 95307, Rarity.RARE, mage.cards.i.InspiredIdea.class)); cards.add(new SetCardInfo("Inspired Ultimatum", 80899, Rarity.RARE, mage.cards.i.InspiredUltimatum.class)); cards.add(new SetCardInfo("Inspiring Refrain", 90034, Rarity.RARE, mage.cards.i.InspiringRefrain.class)); @@ -1352,7 +1334,7 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Island", 40052, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 40062, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 40100, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 53881, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS )); + cards.add(new SetCardInfo("Island", 53881, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Island", 58255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 73634, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 81846, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); @@ -1470,7 +1452,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Kiora, Behemoth Beckoner", 78027, Rarity.UNCOMMON, mage.cards.k.KioraBehemothBeckoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kiora, the Crashing Wave", 59651, Rarity.MYTHIC, mage.cards.k.KioraTheCrashingWave.class)); cards.add(new SetCardInfo("Kird Ape", 31383, Rarity.UNCOMMON, mage.cards.k.KirdApe.class)); - cards.add(new SetCardInfo("Kirin-Touched Orochi", 98047, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class)); cards.add(new SetCardInfo("Kitchen Finks", 36166, Rarity.UNCOMMON, mage.cards.k.KitchenFinks.class)); cards.add(new SetCardInfo("Kiyomaro, First to Stand", 32015, Rarity.RARE, mage.cards.k.KiyomaroFirstToStand.class)); cards.add(new SetCardInfo("Kjeldoran Outpost", 23952, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class, RETRO_ART_USE_VARIOUS)); @@ -1531,7 +1512,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Leaf-Crowned Visionary", 103462, Rarity.RARE, mage.cards.l.LeafCrownedVisionary.class)); cards.add(new SetCardInfo("Leatherback Baloth", 43576, Rarity.UNCOMMON, mage.cards.l.LeatherbackBaloth.class)); cards.add(new SetCardInfo("Ledger Shredder", 99733, Rarity.RARE, mage.cards.l.LedgerShredder.class)); - cards.add(new SetCardInfo("Leeching Lurker", 93988, Rarity.RARE, mage.cards.l.LeechingLurker.class)); cards.add(new SetCardInfo("Legion Angel", 83754, Rarity.RARE, mage.cards.l.LegionAngel.class)); cards.add(new SetCardInfo("Legions to Ashes", 105784, Rarity.RARE, mage.cards.l.LegionsToAshes.class)); cards.add(new SetCardInfo("Leinore, Autumn Sovereign", 94054, Rarity.MYTHIC, mage.cards.l.LeinoreAutumnSovereign.class)); @@ -1569,7 +1549,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Lion Sash", 97887, Rarity.RARE, mage.cards.l.LionSash.class)); cards.add(new SetCardInfo("Lion's Eye Diamond", 51936, Rarity.RARE, mage.cards.l.LionsEyeDiamond.class)); cards.add(new SetCardInfo("Lithoform Engine", 83722, Rarity.MYTHIC, mage.cards.l.LithoformEngine.class)); - cards.add(new SetCardInfo("Living Breakthrough", 97937, Rarity.RARE, mage.cards.l.LivingBreakthrough.class)); cards.add(new SetCardInfo("Living Death", 36042, Rarity.RARE, mage.cards.l.LivingDeath.class, RETRO_ART)); cards.add(new SetCardInfo("Living Wish", 35068, Rarity.RARE, mage.cards.l.LivingWish.class)); cards.add(new SetCardInfo("Livio, Oathsworn Sentinel", 86348, Rarity.RARE, mage.cards.l.LivioOathswornSentinel.class)); @@ -1602,7 +1581,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Loyal Retainers", 47973, Rarity.UNCOMMON, mage.cards.l.LoyalRetainers.class)); cards.add(new SetCardInfo("Loyal Warhound", 92630, Rarity.RARE, mage.cards.l.LoyalWarhound.class)); cards.add(new SetCardInfo("Lu Bu, Master-at-Arms", 36130, Rarity.RARE, mage.cards.l.LuBuMasterAtArms.class, RETRO_ART)); - cards.add(new SetCardInfo("Ludevic's Abomination", 42874, Rarity.RARE, mage.cards.l.LudevicsAbomination.class)); cards.add(new SetCardInfo("Ludevic's Test Subject", 42874, Rarity.RARE, mage.cards.l.LudevicsTestSubject.class)); cards.add(new SetCardInfo("Ludevic, Necro-Alchemist", 86166, Rarity.MYTHIC, mage.cards.l.LudevicNecroAlchemist.class)); cards.add(new SetCardInfo("Lukka, Coppercoat Outcast", 80801, Rarity.MYTHIC, mage.cards.l.LukkaCoppercoatOutcast.class)); @@ -1778,7 +1756,7 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 40054, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 40064, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 40096, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 53877, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS )); + cards.add(new SetCardInfo("Mountain", 53877, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Mountain", 58259, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 73630, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 81864, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -1908,7 +1886,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Nymris, Oona's Trickster", 86342, Rarity.RARE, mage.cards.n.NymrisOonasTrickster.class)); cards.add(new SetCardInfo("Nyx Lotus", 79917, Rarity.RARE, mage.cards.n.NyxLotus.class)); cards.add(new SetCardInfo("Nyxbloom Ancient", 79965, Rarity.MYTHIC, mage.cards.n.NyxbloomAncient.class)); - cards.add(new SetCardInfo("O-Kagachi Made Manifest", 98101, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class)); cards.add(new SetCardInfo("Oakhame Ranger", 78738, Rarity.UNCOMMON, mage.cards.o.OakhameRanger.class)); cards.add(new SetCardInfo("Oath of Druids", 36092, Rarity.RARE, mage.cards.o.OathOfDruids.class, RETRO_ART)); cards.add(new SetCardInfo("Ob Nixilis Reignited", 62509, Rarity.MYTHIC, mage.cards.o.ObNixilisReignited.class)); @@ -2037,7 +2014,7 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Plains", 40066, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 40098, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 48582, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 53879, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS )); + cards.add(new SetCardInfo("Plains", 53879, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Plains", 58253, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 73626, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 81830, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -2058,7 +2035,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Pollywog Symbiote", 80931, Rarity.UNCOMMON, mage.cards.p.PollywogSymbiote.class)); cards.add(new SetCardInfo("Polukranos, Unchained", 79931, Rarity.MYTHIC, mage.cards.p.PolukranosUnchained.class)); cards.add(new SetCardInfo("Ponder", 35118, Rarity.COMMON, mage.cards.p.Ponder.class, FULL_ART)); - cards.add(new SetCardInfo("Poppet Factory", 93918, Rarity.MYTHIC, mage.cards.p.PoppetFactory.class)); cards.add(new SetCardInfo("Poppet Stitcher", 93918, Rarity.MYTHIC, mage.cards.p.PoppetStitcher.class)); cards.add(new SetCardInfo("Porcuparrot", 80965, Rarity.UNCOMMON, mage.cards.p.Porcuparrot.class)); cards.add(new SetCardInfo("Port Razer", 86068, Rarity.MYTHIC, mage.cards.p.PortRazer.class)); @@ -2187,7 +2163,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Red Dragon", 92754, Rarity.UNCOMMON, mage.cards.r.RedDragon.class)); cards.add(new SetCardInfo("Red Elemental Blast", 43610, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); cards.add(new SetCardInfo("Reflecting Pool", 62487, Rarity.RARE, mage.cards.r.ReflectingPool.class)); - cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 98009, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class)); cards.add(new SetCardInfo("Reflections of Littjara", 88252, Rarity.RARE, mage.cards.r.ReflectionsOfLittjara.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reflections of Littjara", 88254, Rarity.RARE, mage.cards.r.ReflectionsOfLittjara.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Regal Leosaur", 80967, Rarity.UNCOMMON, mage.cards.r.RegalLeosaur.class)); @@ -2204,7 +2179,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Reliquary Tower", 69250, Rarity.UNCOMMON, mage.cards.r.ReliquaryTower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reliquary Tower", 86146, Rarity.UNCOMMON, mage.cards.r.ReliquaryTower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Remand", 31429, Rarity.UNCOMMON, mage.cards.r.Remand.class)); - cards.add(new SetCardInfo("Remnant of the Rising Star", 98063, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class)); cards.add(new SetCardInfo("Remove Soul", 35130, Rarity.COMMON, mage.cards.r.RemoveSoul.class, FULL_ART)); cards.add(new SetCardInfo("Renata, Called to the Hunt", 79859, Rarity.UNCOMMON, mage.cards.r.RenataCalledToTheHunt.class)); cards.add(new SetCardInfo("Render Silent", 48576, Rarity.RARE, mage.cards.r.RenderSilent.class)); @@ -2224,7 +2198,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Retaliator Griffin", 43546, Rarity.RARE, mage.cards.r.RetaliatorGriffin.class)); cards.add(new SetCardInfo("Retriever Phoenix", 90094, Rarity.RARE, mage.cards.r.RetrieverPhoenix.class)); cards.add(new SetCardInfo("Return to Dust", 86104, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class)); - cards.add(new SetCardInfo("Revealing Eye", 95351, Rarity.RARE, mage.cards.r.RevealingEye.class)); cards.add(new SetCardInfo("Revenant", 32192, Rarity.RARE, mage.cards.r.Revenant.class, RETRO_ART)); cards.add(new SetCardInfo("Reverse Engineer", 64995, Rarity.UNCOMMON, mage.cards.r.ReverseEngineer.class)); cards.add(new SetCardInfo("Revival Experiment", 90220, Rarity.RARE, mage.cards.r.RevivalExperiment.class)); @@ -2458,7 +2431,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Simic Signet", 62391, Rarity.COMMON, mage.cards.s.SimicSignet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sin Collector", 50112, Rarity.UNCOMMON, mage.cards.s.SinCollector.class)); cards.add(new SetCardInfo("Sinkhole", 43566, Rarity.RARE, mage.cards.s.Sinkhole.class)); - cards.add(new SetCardInfo("Sinner's Judgment", 95279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class)); cards.add(new SetCardInfo("Siphon Insight", 94066, Rarity.RARE, mage.cards.s.SiphonInsight.class)); cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 91211, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class, RETRO_ART)); cards.add(new SetCardInfo("Skarrg Goliath", 47989, Rarity.RARE, mage.cards.s.SkarrgGoliath.class)); @@ -2646,7 +2618,7 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Swamp", 40058, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 40068, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 40092, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 53883, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS )); + cards.add(new SetCardInfo("Swamp", 53883, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_ZEN_VARIOUS)); cards.add(new SetCardInfo("Swamp", 58257, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 73632, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 81856, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); @@ -2861,7 +2833,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Torrent Sculptor", 90248, Rarity.RARE, mage.cards.t.TorrentSculptor.class)); cards.add(new SetCardInfo("Toski, Bearer of Secrets", 88340, Rarity.RARE, mage.cards.t.ToskiBearerOfSecrets.class)); cards.add(new SetCardInfo("Tourach, Dread Cantor", 91253, Rarity.MYTHIC, mage.cards.t.TourachDreadCantor.class)); - cards.add(new SetCardInfo("Tovolar's Magehunter", 43507, Rarity.RARE, mage.cards.t.TovolarsMagehunter.class)); cards.add(new SetCardInfo("Toxic Deluge", 82832, Rarity.RARE, mage.cards.t.ToxicDeluge.class)); cards.add(new SetCardInfo("Tradewind Rider", 36048, Rarity.RARE, mage.cards.t.TradewindRider.class, RETRO_ART)); cards.add(new SetCardInfo("Training Center", 85954, Rarity.RARE, mage.cards.t.TrainingCenter.class)); @@ -2918,7 +2889,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Uktabi Orangutan", 36016, Rarity.UNCOMMON, mage.cards.u.UktabiOrangutan.class, RETRO_ART)); cards.add(new SetCardInfo("Ulamog, the Infinite Gyre", 102345, Rarity.MYTHIC, mage.cards.u.UlamogTheInfiniteGyre.class)); cards.add(new SetCardInfo("Ultimate Price", 58269, Rarity.UNCOMMON, mage.cards.u.UltimatePrice.class)); - cards.add(new SetCardInfo("Ulvenwald Behemoth", 95421, Rarity.RARE, mage.cards.u.UlvenwaldBehemoth.class)); cards.add(new SetCardInfo("Ulvenwald Observer", 61553, Rarity.RARE, mage.cards.u.UlvenwaldObserver.class)); cards.add(new SetCardInfo("Ulvenwald Oddity", 95421, Rarity.RARE, mage.cards.u.UlvenwaldOddity.class)); cards.add(new SetCardInfo("Umezawa's Jitte", 36210, Rarity.RARE, mage.cards.u.UmezawasJitte.class)); @@ -2989,7 +2959,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Verazol, the Split Current", 83820, Rarity.RARE, mage.cards.v.VerazolTheSplitCurrent.class)); cards.add(new SetCardInfo("Verdant Catacombs", 91403, Rarity.RARE, mage.cards.v.VerdantCatacombs.class)); cards.add(new SetCardInfo("Verdant Mastery", 90138, Rarity.RARE, mage.cards.v.VerdantMastery.class)); - cards.add(new SetCardInfo("Vessel of the All-Consuming", 98105, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class)); cards.add(new SetCardInfo("Vesuvan Duplimancy", 103402, Rarity.MYTHIC, mage.cards.v.VesuvanDuplimancy.class)); cards.add(new SetCardInfo("Vexing Shusher", 32533, Rarity.RARE, mage.cards.v.VexingShusher.class)); cards.add(new SetCardInfo("Veyran, Voice of Duality", 90282, Rarity.MYTHIC, mage.cards.v.VeyranVoiceOfDuality.class)); @@ -3053,7 +3022,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Weathered Wayfarer", 102223, Rarity.RARE, mage.cards.w.WeatheredWayfarer.class)); cards.add(new SetCardInfo("Weaver of Harmony", 98031, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class)); cards.add(new SetCardInfo("Wedding Announcement", 95267, Rarity.RARE, mage.cards.w.WeddingAnnouncement.class)); - cards.add(new SetCardInfo("Wedding Festivity", 95267, Rarity.RARE, mage.cards.w.WeddingFestivity.class)); cards.add(new SetCardInfo("Wee Dragonauts", 35174, Rarity.COMMON, mage.cards.w.WeeDragonauts.class)); cards.add(new SetCardInfo("Werewolf Pack Leader", 92760, Rarity.RARE, mage.cards.w.WerewolfPackLeader.class)); cards.add(new SetCardInfo("Wheel and Deal", 62411, Rarity.RARE, mage.cards.w.WheelAndDeal.class)); @@ -3072,7 +3040,6 @@ public class MagicOnlinePromos extends ExpansionSet { cards.add(new SetCardInfo("Wild-Magic Sorcerer", 92752, Rarity.RARE, mage.cards.w.WildMagicSorcerer.class)); cards.add(new SetCardInfo("Wildcall", 55749, Rarity.RARE, mage.cards.w.Wildcall.class)); cards.add(new SetCardInfo("Wildfire Eternal", 64989, Rarity.RARE, mage.cards.w.WildfireEternal.class)); - cards.add(new SetCardInfo("Wildsong Howler", 95425, Rarity.RARE, mage.cards.w.WildsongHowler.class)); cards.add(new SetCardInfo("Willbender", 36258, Rarity.UNCOMMON, mage.cards.w.Willbender.class)); cards.add(new SetCardInfo("Willow Geist", 94024, Rarity.RARE, mage.cards.w.WillowGeist.class)); cards.add(new SetCardInfo("Willowdusk, Essence Seer", 90288, Rarity.MYTHIC, mage.cards.w.WillowduskEssenceSeer.class)); diff --git a/Mage.Sets/src/mage/sets/MagicOrigins.java b/Mage.Sets/src/mage/sets/MagicOrigins.java index 5b3187549d1..c7aef8f2e7f 100644 --- a/Mage.Sets/src/mage/sets/MagicOrigins.java +++ b/Mage.Sets/src/mage/sets/MagicOrigins.java @@ -72,7 +72,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Caves of Koilos", 245, Rarity.RARE, mage.cards.c.CavesOfKoilos.class)); cards.add(new SetCardInfo("Celestial Flare", 8, Rarity.COMMON, mage.cards.c.CelestialFlare.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 135, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 135, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Chandra's Fury", 136, Rarity.COMMON, mage.cards.c.ChandrasFury.class)); cards.add(new SetCardInfo("Chandra's Ignition", 137, Rarity.RARE, mage.cards.c.ChandrasIgnition.class)); cards.add(new SetCardInfo("Charging Griffin", 9, Rarity.COMMON, mage.cards.c.ChargingGriffin.class)); @@ -133,7 +132,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Gather the Pack", 178, Rarity.UNCOMMON, mage.cards.g.GatherThePack.class)); cards.add(new SetCardInfo("Ghirapur Aether Grid", 148, Rarity.UNCOMMON, mage.cards.g.GhirapurAetherGrid.class)); cards.add(new SetCardInfo("Ghirapur Gearcrafter", 149, Rarity.COMMON, mage.cards.g.GhirapurGearcrafter.class)); - cards.add(new SetCardInfo("Gideon, Battle-Forged", 23, Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); cards.add(new SetCardInfo("Gideon's Phalanx", 14, Rarity.RARE, mage.cards.g.GideonsPhalanx.class)); cards.add(new SetCardInfo("Gilt-Leaf Winnower", 99, Rarity.RARE, mage.cards.g.GiltLeafWinnower.class)); cards.add(new SetCardInfo("Gnarlroot Trapper", 100, Rarity.UNCOMMON, mage.cards.g.GnarlrootTrapper.class)); @@ -165,7 +163,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Island", 259, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 260, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jace's Sanctum", 61, Rarity.RARE, mage.cards.j.JacesSanctum.class)); - cards.add(new SetCardInfo("Jace, Telepath Unbound", 60, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 60, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); cards.add(new SetCardInfo("Jayemdae Tome", 231, Rarity.UNCOMMON, mage.cards.j.JayemdaeTome.class)); cards.add(new SetCardInfo("Jhessian Thief", 62, Rarity.UNCOMMON, mage.cards.j.JhessianThief.class)); @@ -180,7 +177,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Languish", 105, Rarity.RARE, mage.cards.l.Languish.class)); cards.add(new SetCardInfo("Leaf Gilder", 184, Rarity.COMMON, mage.cards.l.LeafGilder.class)); cards.add(new SetCardInfo("Lightning Javelin", 153, Rarity.COMMON, mage.cards.l.LightningJavelin.class)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", 106, Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", 106, Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); cards.add(new SetCardInfo("Llanowar Empath", 185, Rarity.COMMON, mage.cards.l.LlanowarEmpath.class)); cards.add(new SetCardInfo("Llanowar Wastes", 248, Rarity.RARE, mage.cards.l.LlanowarWastes.class)); @@ -210,7 +206,6 @@ public final class MagicOrigins extends ExpansionSet { cards.add(new SetCardInfo("Negate", 65, Rarity.COMMON, mage.cards.n.Negate.class)); cards.add(new SetCardInfo("Nightmare", 282, Rarity.RARE, mage.cards.n.Nightmare.class)); cards.add(new SetCardInfo("Nightsnare", 111, Rarity.COMMON, mage.cards.n.Nightsnare.class)); - cards.add(new SetCardInfo("Nissa, Sage Animist", 189, Rarity.MYTHIC, mage.cards.n.NissaSageAnimist.class)); cards.add(new SetCardInfo("Nissa's Pilgrimage", 190, Rarity.COMMON, mage.cards.n.NissasPilgrimage.class)); cards.add(new SetCardInfo("Nissa's Revelation", 191, Rarity.RARE, mage.cards.n.NissasRevelation.class)); cards.add(new SetCardInfo("Nissa, Vastwood Seer", 189, Rarity.MYTHIC, mage.cards.n.NissaVastwoodSeer.class)); diff --git a/Mage.Sets/src/mage/sets/MagicOriginsPromos.java b/Mage.Sets/src/mage/sets/MagicOriginsPromos.java index b76caff8a79..6966005667f 100644 --- a/Mage.Sets/src/mage/sets/MagicOriginsPromos.java +++ b/Mage.Sets/src/mage/sets/MagicOriginsPromos.java @@ -25,7 +25,6 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Alhammarret, High Arbiter", "43s", Rarity.RARE, mage.cards.a.AlhammarretHighArbiter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra's Ignition", "137s", Rarity.RARE, mage.cards.c.ChandrasIgnition.class)); cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", "135s", Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", "135s", Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); cards.add(new SetCardInfo("Conclave Naturalists", 171, Rarity.UNCOMMON, mage.cards.c.ConclaveNaturalists.class)); cards.add(new SetCardInfo("Dark Petition", "90s", Rarity.RARE, mage.cards.d.DarkPetition.class)); cards.add(new SetCardInfo("Despoiler of Souls", "93s", Rarity.RARE, mage.cards.d.DespoilerOfSouls.class)); @@ -36,7 +35,6 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Exquisite Firecraft", "143s", Rarity.RARE, mage.cards.e.ExquisiteFirecraft.class)); cards.add(new SetCardInfo("Gaea's Revenge", "177s", Rarity.RARE, mage.cards.g.GaeasRevenge.class)); cards.add(new SetCardInfo("Gideon's Phalanx", "14s", Rarity.RARE, mage.cards.g.GideonsPhalanx.class)); - cards.add(new SetCardInfo("Gideon, Battle-Forged", "23s", Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); cards.add(new SetCardInfo("Gilt-Leaf Winnower", "99s", Rarity.RARE, mage.cards.g.GiltLeafWinnower.class)); cards.add(new SetCardInfo("Goblin Piledriver", "151s", Rarity.RARE, mage.cards.g.GoblinPiledriver.class)); cards.add(new SetCardInfo("Graveblade Marauder", "101s", Rarity.RARE, mage.cards.g.GravebladeMarauder.class)); @@ -44,7 +42,6 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Hixus, Prison Warden", 19, Rarity.RARE, mage.cards.h.HixusPrisonWarden.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hixus, Prison Warden", "19s", Rarity.RARE, mage.cards.h.HixusPrisonWarden.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Honored Hierarch", "182s", Rarity.RARE, mage.cards.h.HonoredHierarch.class)); - cards.add(new SetCardInfo("Jace, Telepath Unbound", "60s", Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", "60s", Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); cards.add(new SetCardInfo("Knight of the White Orchid", "21s", Rarity.RARE, mage.cards.k.KnightOfTheWhiteOrchid.class)); cards.add(new SetCardInfo("Kothophed, Soul Hoarder", 104, Rarity.RARE, mage.cards.k.KothophedSoulHoarder.class, NON_FULL_USE_VARIOUS)); @@ -53,13 +50,11 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Kytheon, Hero of Akros", "23s", Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class)); cards.add(new SetCardInfo("Languish", 105, Rarity.RARE, mage.cards.l.Languish.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Languish", "105s", Rarity.RARE, mage.cards.l.Languish.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", "106s", Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", "106s", Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); cards.add(new SetCardInfo("Managorger Hydra", "186s", Rarity.RARE, mage.cards.m.ManagorgerHydra.class)); cards.add(new SetCardInfo("Mizzium Meddler", 64, Rarity.RARE, mage.cards.m.MizziumMeddler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mizzium Meddler", "64s", Rarity.RARE, mage.cards.m.MizziumMeddler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nissa's Revelation", "191s", Rarity.RARE, mage.cards.n.NissasRevelation.class)); - cards.add(new SetCardInfo("Nissa, Sage Animist", "189s", Rarity.MYTHIC, mage.cards.n.NissaSageAnimist.class)); cards.add(new SetCardInfo("Nissa, Vastwood Seer", "189s", Rarity.MYTHIC, mage.cards.n.NissaVastwoodSeer.class)); cards.add(new SetCardInfo("Outland Colossus", "193s", Rarity.RARE, mage.cards.o.OutlandColossus.class)); cards.add(new SetCardInfo("Pia and Kiran Nalaar", 157, Rarity.RARE, mage.cards.p.PiaAndKiranNalaar.class, NON_FULL_USE_VARIOUS)); @@ -74,5 +69,5 @@ public class MagicOriginsPromos extends ExpansionSet { cards.add(new SetCardInfo("Tragic Arrogance", "38s", Rarity.RARE, mage.cards.t.TragicArrogance.class)); cards.add(new SetCardInfo("Vryn Wingmare", "40s", Rarity.RARE, mage.cards.v.VrynWingmare.class)); cards.add(new SetCardInfo("Willbreaker", "84s", Rarity.RARE, mage.cards.w.Willbreaker.class)); - } + } } diff --git a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java index 4a286cd8326..03bc2d1c727 100644 --- a/Mage.Sets/src/mage/sets/MarchOfTheMachine.java +++ b/Mage.Sets/src/mage/sets/MarchOfTheMachine.java @@ -2,15 +2,15 @@ package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; -import mage.util.RandomUtil; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardRepository; 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.ArrayList; import java.util.List; @@ -41,7 +41,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Aerial Boost", 2, Rarity.COMMON, mage.cards.a.AerialBoost.class)); cards.add(new SetCardInfo("Aetherblade Agent", 88, Rarity.COMMON, mage.cards.a.AetherbladeAgent.class)); - cards.add(new SetCardInfo("Aetherwing, Golden-Scale Flagship", 234, Rarity.UNCOMMON, mage.cards.a.AetherwingGoldenScaleFlagship.class)); cards.add(new SetCardInfo("Akki Scrapchomper", 130, Rarity.COMMON, mage.cards.a.AkkiScrapchomper.class)); cards.add(new SetCardInfo("Alabaster Host Intercessor", 3, Rarity.COMMON, mage.cards.a.AlabasterHostIntercessor.class)); cards.add(new SetCardInfo("Alabaster Host Sanctifier", 4, Rarity.COMMON, mage.cards.a.AlabasterHostSanctifier.class)); @@ -54,33 +53,24 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Archpriest of Shadows", 356, Rarity.RARE, mage.cards.a.ArchpriestOfShadows.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archpriest of Shadows", 89, Rarity.RARE, mage.cards.a.ArchpriestOfShadows.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Artistic Refusal", 46, Rarity.UNCOMMON, mage.cards.a.ArtisticRefusal.class)); - cards.add(new SetCardInfo("Ashen Reaper", 232, Rarity.UNCOMMON, mage.cards.a.AshenReaper.class)); cards.add(new SetCardInfo("Assimilate Essence", 47, Rarity.COMMON, mage.cards.a.AssimilateEssence.class)); cards.add(new SetCardInfo("Astral Wingspan", 48, Rarity.UNCOMMON, mage.cards.a.AstralWingspan.class)); cards.add(new SetCardInfo("Atraxa's Fall", 176, Rarity.COMMON, mage.cards.a.AtraxasFall.class)); cards.add(new SetCardInfo("Attentive Skywarden", 7, Rarity.COMMON, mage.cards.a.AttentiveSkywarden.class)); - cards.add(new SetCardInfo("Awaken the Maelstrom", 230, Rarity.RARE, mage.cards.a.AwakenTheMaelstrom.class)); - cards.add(new SetCardInfo("Awakened Skyclave", 194, Rarity.UNCOMMON, mage.cards.a.AwakenedSkyclave.class)); cards.add(new SetCardInfo("Axgard Artisan", 332, Rarity.UNCOMMON, mage.cards.a.AxgardArtisan.class)); - cards.add(new SetCardInfo("Ayara, Furnace Queen", 296, Rarity.RARE, mage.cards.a.AyaraFurnaceQueen.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ayara, Furnace Queen", 90, Rarity.RARE, mage.cards.a.AyaraFurnaceQueen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ayara, Widow of the Realm", 296, Rarity.RARE, mage.cards.a.AyaraWidowOfTheRealm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ayara, Widow of the Realm", 90, Rarity.RARE, mage.cards.a.AyaraWidowOfTheRealm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baral and Kari Zev", 218, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baral and Kari Zev", 302, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Beamtown Beatstick", 131, Rarity.COMMON, mage.cards.b.BeamtownBeatstick.class)); - cards.add(new SetCardInfo("Belenon War Anthem", 20, Rarity.UNCOMMON, mage.cards.b.BelenonWarAnthem.class)); - cards.add(new SetCardInfo("Belligerent Regisaur", 191, Rarity.RARE, mage.cards.b.BelligerentRegisaur.class)); cards.add(new SetCardInfo("Bladed Battle-Fan", 91, Rarity.COMMON, mage.cards.b.BladedBattleFan.class)); cards.add(new SetCardInfo("Blighted Burgeoning", 177, Rarity.COMMON, mage.cards.b.BlightedBurgeoning.class)); cards.add(new SetCardInfo("Blightreaper Thallid", 92, Rarity.UNCOMMON, mage.cards.b.BlightreaperThallid.class)); - cards.add(new SetCardInfo("Blightsower Thallid", 92, Rarity.UNCOMMON, mage.cards.b.BlightsowerThallid.class)); cards.add(new SetCardInfo("Bloated Processor", 357, Rarity.RARE, mage.cards.b.BloatedProcessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloated Processor", 93, Rarity.RARE, mage.cards.b.BloatedProcessor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodfeather Phoenix", 132, Rarity.RARE, mage.cards.b.BloodfeatherPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodfeather Phoenix", 362, Rarity.RARE, mage.cards.b.BloodfeatherPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodfell Caves", 267, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); - cards.add(new SetCardInfo("Bloomwielder Dryads", 237, Rarity.UNCOMMON, mage.cards.b.BloomwielderDryads.class)); cards.add(new SetCardInfo("Blossoming Sands", 268, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); cards.add(new SetCardInfo("Bola Slinger", 8, Rarity.COMMON, mage.cards.b.BolaSlinger.class)); cards.add(new SetCardInfo("Bonded Herdbeast", 178, Rarity.COMMON, mage.cards.b.BondedHerdbeast.class)); @@ -93,21 +83,17 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Breach the Multiverse", 358, Rarity.RARE, mage.cards.b.BreachTheMultiverse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Breach the Multiverse", 94, Rarity.RARE, mage.cards.b.BreachTheMultiverse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Burning Sun's Fury", 133, Rarity.COMMON, mage.cards.b.BurningSunsFury.class)); - cards.add(new SetCardInfo("Burnished Dunestomper", 43, Rarity.COMMON, mage.cards.b.BurnishedDunestomper.class)); - cards.add(new SetCardInfo("Caetus, Sea Tyrant of Segovia", 63, Rarity.RARE, mage.cards.c.CaetusSeaTyrantOfSegovia.class)); cards.add(new SetCardInfo("Captive Weird", 49, Rarity.UNCOMMON, mage.cards.c.CaptiveWeird.class)); cards.add(new SetCardInfo("Chandra, Hope's Beacon", 134, Rarity.MYTHIC, mage.cards.c.ChandraHopesBeacon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra, Hope's Beacon", 321, Rarity.MYTHIC, mage.cards.c.ChandraHopesBeacon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Change the Equation", 50, Rarity.UNCOMMON, mage.cards.c.ChangeTheEquation.class)); cards.add(new SetCardInfo("Chomping Kavu", 179, Rarity.COMMON, mage.cards.c.ChompingKavu.class)); - cards.add(new SetCardInfo("Chrome Host Hulk", 188, Rarity.UNCOMMON, mage.cards.c.ChromeHostHulk.class)); cards.add(new SetCardInfo("Chrome Host Seedshark", 350, Rarity.RARE, mage.cards.c.ChromeHostSeedshark.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chrome Host Seedshark", 51, Rarity.RARE, mage.cards.c.ChromeHostSeedshark.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("City on Fire", 135, Rarity.RARE, mage.cards.c.CityOnFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("City on Fire", 363, Rarity.RARE, mage.cards.c.CityOnFire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Collective Nightmare", 95, Rarity.UNCOMMON, mage.cards.c.CollectiveNightmare.class)); cards.add(new SetCardInfo("Coming In Hot", 136, Rarity.COMMON, mage.cards.c.ComingInHot.class)); - cards.add(new SetCardInfo("Compleated Conjurer", 49, Rarity.UNCOMMON, mage.cards.c.CompleatedConjurer.class)); cards.add(new SetCardInfo("Compleated Huntmaster", 96, Rarity.UNCOMMON, mage.cards.c.CompleatedHuntmaster.class)); cards.add(new SetCardInfo("Complete the Circuit", 351, Rarity.RARE, mage.cards.c.CompleteTheCircuit.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Complete the Circuit", 52, Rarity.RARE, mage.cards.c.CompleteTheCircuit.class, NON_FULL_USE_VARIOUS)); @@ -123,9 +109,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Deadly Derision", 99, Rarity.COMMON, mage.cards.d.DeadlyDerision.class)); cards.add(new SetCardInfo("Deeproot Wayfinder", 184, Rarity.RARE, mage.cards.d.DeeprootWayfinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deeproot Wayfinder", 369, Rarity.RARE, mage.cards.d.DeeprootWayfinder.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Defiant Thundermaw", 149, Rarity.MYTHIC, mage.cards.d.DefiantThundermaw.class)); - cards.add(new SetCardInfo("Deluge of the Dead", 115, Rarity.MYTHIC, mage.cards.d.DelugeOfTheDead.class)); - cards.add(new SetCardInfo("Disciples of the Inferno", 148, Rarity.UNCOMMON, mage.cards.d.DisciplesOfTheInferno.class)); cards.add(new SetCardInfo("Dismal Backwater", 269, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Disturbing Conversion", 54, Rarity.COMMON, mage.cards.d.DisturbingConversion.class)); cards.add(new SetCardInfo("Djeru and Hazoret", 221, Rarity.RARE, mage.cards.d.DjeruAndHazoret.class, NON_FULL_USE_VARIOUS)); @@ -144,15 +127,12 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Elvish Vatkeeper", 223, Rarity.UNCOMMON, mage.cards.e.ElvishVatkeeper.class)); cards.add(new SetCardInfo("Enduring Bondwarden", 14, Rarity.COMMON, mage.cards.e.EnduringBondwarden.class)); cards.add(new SetCardInfo("Ephara's Dispersal", 55, Rarity.COMMON, mage.cards.e.EpharasDispersal.class)); - cards.add(new SetCardInfo("Ephara, Ever-Sheltering", 23, Rarity.RARE, mage.cards.e.EpharaEverSheltering.class)); cards.add(new SetCardInfo("Errant and Giada", 224, Rarity.RARE, mage.cards.e.ErrantAndGiada.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Errant and Giada", 306, Rarity.RARE, mage.cards.e.ErrantAndGiada.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Essence of Orthodoxy", 323, Rarity.RARE, mage.cards.e.EssenceOfOrthodoxy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Essence of Orthodoxy", 376, Rarity.RARE, mage.cards.e.EssenceOfOrthodoxy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etali, Primal Conqueror", 137, Rarity.RARE, mage.cards.e.EtaliPrimalConqueror.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etali, Primal Conqueror", 298, Rarity.RARE, mage.cards.e.EtaliPrimalConqueror.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Sickness", 137, Rarity.RARE, mage.cards.e.EtaliPrimalSickness.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Sickness", 298, Rarity.RARE, mage.cards.e.EtaliPrimalSickness.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Etched Familiar", 101, Rarity.COMMON, mage.cards.e.EtchedFamiliar.class)); cards.add(new SetCardInfo("Etched Host Doombringer", 102, Rarity.COMMON, mage.cards.e.EtchedHostDoombringer.class)); cards.add(new SetCardInfo("Expedition Lookout", 56, Rarity.COMMON, mage.cards.e.ExpeditionLookout.class)); @@ -172,30 +152,23 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Furnace Gremlin", 139, Rarity.UNCOMMON, mage.cards.f.FurnaceGremlin.class)); cards.add(new SetCardInfo("Furnace Host Charger", 140, Rarity.COMMON, mage.cards.f.FurnaceHostCharger.class)); cards.add(new SetCardInfo("Furnace Reins", 141, Rarity.UNCOMMON, mage.cards.f.FurnaceReins.class)); - cards.add(new SetCardInfo("Furnace-Blessed Conqueror", 38, Rarity.UNCOMMON, mage.cards.f.FurnaceBlessedConqueror.class)); cards.add(new SetCardInfo("Furtive Analyst", 59, Rarity.COMMON, mage.cards.f.FurtiveAnalyst.class)); - cards.add(new SetCardInfo("Gargantuan Slabhorn", 240, Rarity.UNCOMMON, mage.cards.g.GargantuanSlabhorn.class)); cards.add(new SetCardInfo("Ghalta and Mavren", 225, Rarity.RARE, mage.cards.g.GhaltaAndMavren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghalta and Mavren", 307, Rarity.RARE, mage.cards.g.GhaltaAndMavren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghalta and Mavren", 386, Rarity.RARE, mage.cards.g.GhaltaAndMavren.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gift of Compleation", 106, Rarity.UNCOMMON, mage.cards.g.GiftOfCompleation.class)); - cards.add(new SetCardInfo("Gitaxian Mindstinger", 88, Rarity.COMMON, mage.cards.g.GitaxianMindstinger.class)); - cards.add(new SetCardInfo("Gitaxian Spellstalker", 151, Rarity.UNCOMMON, mage.cards.g.GitaxianSpellstalker.class)); cards.add(new SetCardInfo("Glissa, Herald of Predation", 226, Rarity.RARE, mage.cards.g.GlissaHeraldOfPredation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glissa, Herald of Predation", 308, Rarity.RARE, mage.cards.g.GlissaHeraldOfPredation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glistening Dawn", 187, Rarity.RARE, mage.cards.g.GlisteningDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glistening Dawn", 371, Rarity.RARE, mage.cards.g.GlisteningDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glistening Deluge", 107, Rarity.UNCOMMON, mage.cards.g.GlisteningDeluge.class)); - cards.add(new SetCardInfo("Glistening Goremonger", 157, Rarity.COMMON, mage.cards.g.GlisteningGoremonger.class)); cards.add(new SetCardInfo("Gloomfang Mauler", 108, Rarity.COMMON, mage.cards.g.GloomfangMauler.class)); cards.add(new SetCardInfo("Gnottvold Hermit", 188, Rarity.UNCOMMON, mage.cards.g.GnottvoldHermit.class)); cards.add(new SetCardInfo("Golden-Scale Aeronaut", 15, Rarity.COMMON, mage.cards.g.GoldenScaleAeronaut.class)); cards.add(new SetCardInfo("Grafted Butcher", 109, Rarity.RARE, mage.cards.g.GraftedButcher.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grafted Butcher", 359, Rarity.RARE, mage.cards.g.GraftedButcher.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grandmother Ravi Sengir", 116, Rarity.UNCOMMON, mage.cards.g.GrandmotherRaviSengir.class)); cards.add(new SetCardInfo("Guardian of Ghirapur", 16, Rarity.RARE, mage.cards.g.GuardianOfGhirapur.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Guardian of Ghirapur", 345, Rarity.RARE, mage.cards.g.GuardianOfGhirapur.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Guildpact Paragon", 1, Rarity.MYTHIC, mage.cards.g.GuildpactParagon.class)); cards.add(new SetCardInfo("Halo Forager", 227, Rarity.UNCOMMON, mage.cards.h.HaloForager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Halo Forager", 385, Rarity.UNCOMMON, mage.cards.h.HaloForager.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Halo Hopper", 260, Rarity.COMMON, mage.cards.h.HaloHopper.class)); @@ -204,15 +177,11 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Harried Artisan", 143, Rarity.UNCOMMON, mage.cards.h.HarriedArtisan.class)); cards.add(new SetCardInfo("Heliod, the Radiant Dawn", 17, Rarity.RARE, mage.cards.h.HeliodTheRadiantDawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heliod, the Radiant Dawn", 293, Rarity.RARE, mage.cards.h.HeliodTheRadiantDawn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Heliod, the Warped Eclipse", 17, Rarity.RARE, mage.cards.h.HeliodTheWarpedEclipse.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Heliod, the Warped Eclipse", 293, Rarity.RARE, mage.cards.h.HeliodTheWarpedEclipse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Herbology Instructor", 189, Rarity.UNCOMMON, mage.cards.h.HerbologyInstructor.class)); - cards.add(new SetCardInfo("Hideous Fleshwheeler", 119, Rarity.UNCOMMON, mage.cards.h.HideousFleshwheeler.class)); cards.add(new SetCardInfo("Hidetsugu and Kairi", 228, Rarity.RARE, mage.cards.h.HidetsuguAndKairi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hidetsugu and Kairi", 309, Rarity.RARE, mage.cards.h.HidetsuguAndKairi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hoarding Broodlord", 110, Rarity.RARE, mage.cards.h.HoardingBroodlord.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hoarding Broodlord", 360, Rarity.RARE, mage.cards.h.HoardingBroodlord.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Holy Frazzle-Cannon", 238, Rarity.UNCOMMON, mage.cards.h.HolyFrazzleCannon.class)); cards.add(new SetCardInfo("Ichor Drinker", 111, Rarity.COMMON, mage.cards.i.IchorDrinker.class)); cards.add(new SetCardInfo("Ichor Shade", 112, Rarity.COMMON, mage.cards.i.IchorShade.class)); cards.add(new SetCardInfo("Infected Defector", 18, Rarity.COMMON, mage.cards.i.InfectedDefector.class)); @@ -260,7 +229,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Invasion of Vryn", 64, Rarity.UNCOMMON, mage.cards.i.InvasionOfVryn.class)); cards.add(new SetCardInfo("Invasion of Xerex", 242, Rarity.UNCOMMON, mage.cards.i.InvasionOfXerex.class)); cards.add(new SetCardInfo("Invasion of Zendikar", 194, Rarity.UNCOMMON, mage.cards.i.InvasionOfZendikar.class)); - cards.add(new SetCardInfo("Invocation of the Founders", 61, Rarity.RARE, mage.cards.i.InvocationOfTheFounders.class)); cards.add(new SetCardInfo("Iridescent Blademaster", 195, Rarity.COMMON, mage.cards.i.IridescentBlademaster.class)); cards.add(new SetCardInfo("Island", 278, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 284, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); @@ -284,14 +252,8 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Kor Halberd", 27, Rarity.COMMON, mage.cards.k.KorHalberd.class)); cards.add(new SetCardInfo("Kroxa and Kunoros", 245, Rarity.MYTHIC, mage.cards.k.KroxaAndKunoros.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kroxa and Kunoros", 312, Rarity.MYTHIC, mage.cards.k.KroxaAndKunoros.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kyren Flamewright", 147, Rarity.UNCOMMON, mage.cards.k.KyrenFlamewright.class)); - cards.add(new SetCardInfo("Lazotep Convert", 231, Rarity.UNCOMMON, mage.cards.l.LazotepConvert.class)); - cards.add(new SetCardInfo("Leyline Surge", 193, Rarity.MYTHIC, mage.cards.l.LeylineSurge.class)); - cards.add(new SetCardInfo("Lightshield Array", 22, Rarity.RARE, mage.cards.l.LightshieldArray.class)); cards.add(new SetCardInfo("Lithomantic Barrage", 152, Rarity.UNCOMMON, mage.cards.l.LithomanticBarrage.class)); - cards.add(new SetCardInfo("Malady Invoker", 189, Rarity.UNCOMMON, mage.cards.m.MaladyInvoker.class)); cards.add(new SetCardInfo("Marauding Dreadship", 153, Rarity.COMMON, mage.cards.m.MaraudingDreadship.class)); - cards.add(new SetCardInfo("Marchesa, Resolute Monarch", 114, Rarity.RARE, mage.cards.m.MarchesaResoluteMonarch.class)); cards.add(new SetCardInfo("Marshal of Zhalfir", 246, Rarity.UNCOMMON, mage.cards.m.MarshalOfZhalfir.class)); cards.add(new SetCardInfo("Meeting of Minds", 66, Rarity.COMMON, mage.cards.m.MeetingOfMinds.class)); cards.add(new SetCardInfo("Merciless Repurposing", 117, Rarity.UNCOMMON, mage.cards.m.MercilessRepurposing.class)); @@ -319,12 +281,10 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Omnath, Locus of All", 387, Rarity.RARE, mage.cards.o.OmnathLocusOfAll.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Onakke Javelineer", 156, Rarity.COMMON, mage.cards.o.OnakkeJavelineer.class)); cards.add(new SetCardInfo("Oracle of Tragedy", 71, Rarity.UNCOMMON, mage.cards.o.OracleOfTragedy.class)); - cards.add(new SetCardInfo("Order of the Alabaster Host", 72, Rarity.COMMON, mage.cards.o.OrderOfTheAlabasterHost.class)); cards.add(new SetCardInfo("Order of the Mirror", 72, Rarity.COMMON, mage.cards.o.OrderOfTheMirror.class)); cards.add(new SetCardInfo("Orthion, Hero of Lavabrink", 334, Rarity.RARE, mage.cards.o.OrthionHeroOfLavabrink.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Orthion, Hero of Lavabrink", 379, Rarity.RARE, mage.cards.o.OrthionHeroOfLavabrink.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Overgrown Pest", 197, Rarity.COMMON, mage.cards.o.OvergrownPest.class)); - cards.add(new SetCardInfo("Overloaded Mage-Ring", 64, Rarity.UNCOMMON, mage.cards.o.OverloadedMageRing.class)); cards.add(new SetCardInfo("Ozolith, the Shattered Spire", 198, Rarity.RARE, mage.cards.o.OzolithTheShatteredSpire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ozolith, the Shattered Spire", 372, Rarity.RARE, mage.cards.o.OzolithTheShatteredSpire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Phyrexian Archivist", 262, Rarity.COMMON, mage.cards.p.PhyrexianArchivist.class)); @@ -332,26 +292,19 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Phyrexian Censor", 31, Rarity.UNCOMMON, mage.cards.p.PhyrexianCensor.class)); cards.add(new SetCardInfo("Phyrexian Gargantua", 121, Rarity.UNCOMMON, mage.cards.p.PhyrexianGargantua.class)); cards.add(new SetCardInfo("Phyrexian Pegasus", 324, Rarity.COMMON, mage.cards.p.PhyrexianPegasus.class)); - cards.add(new SetCardInfo("Phyrexian Skyflayer", 143, Rarity.UNCOMMON, mage.cards.p.PhyrexianSkyflayer.class)); cards.add(new SetCardInfo("Pile On", 122, Rarity.RARE, mage.cards.p.PileOn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Pile On", 361, Rarity.RARE, mage.cards.p.PileOn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Placid Rottentail", 199, Rarity.COMMON, mage.cards.p.PlacidRottentail.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 282, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 283, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Plated Kilnbeast", 178, Rarity.COMMON, mage.cards.p.PlatedKilnbeast.class)); cards.add(new SetCardInfo("Polukranos Reborn", 200, Rarity.RARE, mage.cards.p.PolukranosReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Polukranos Reborn", 300, Rarity.RARE, mage.cards.p.PolukranosReborn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polukranos, Engine of Ruin", 200, Rarity.RARE, mage.cards.p.PolukranosEngineOfRuin.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polukranos, Engine of Ruin", 300, Rarity.RARE, mage.cards.p.PolukranosEngineOfRuin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Portent Tracker", 201, Rarity.COMMON, mage.cards.p.PortentTracker.class)); cards.add(new SetCardInfo("Preening Champion", 73, Rarity.COMMON, mage.cards.p.PreeningChampion.class)); - cards.add(new SetCardInfo("Prickle Faeries", 113, Rarity.UNCOMMON, mage.cards.p.PrickleFaeries.class)); - cards.add(new SetCardInfo("Primordial Plasm", 192, Rarity.UNCOMMON, mage.cards.p.PrimordialPlasm.class)); cards.add(new SetCardInfo("Progenitor Exarch", 32, Rarity.RARE, mage.cards.p.ProgenitorExarch.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Progenitor Exarch", 348, Rarity.RARE, mage.cards.p.ProgenitorExarch.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Protocol Knight", 74, Rarity.COMMON, mage.cards.p.ProtocolKnight.class)); - cards.add(new SetCardInfo("Pyre of the World Tree", 145, Rarity.RARE, mage.cards.p.PyreOfTheWorldTree.class)); cards.add(new SetCardInfo("Pyretic Prankster", 157, Rarity.COMMON, mage.cards.p.PyreticPrankster.class)); cards.add(new SetCardInfo("Quintorius, Loremaster", 250, Rarity.RARE, mage.cards.q.QuintoriusLoremaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Quintorius, Loremaster", 314, Rarity.RARE, mage.cards.q.QuintoriusLoremaster.class, NON_FULL_USE_VARIOUS)); @@ -368,13 +321,9 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Realmbreaker, the Invasion Tree", 374, Rarity.RARE, mage.cards.r.RealmbreakerTheInvasionTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Redcap Heelslasher", 161, Rarity.COMMON, mage.cards.r.RedcapHeelslasher.class)); cards.add(new SetCardInfo("Referee Squad", 327, Rarity.UNCOMMON, mage.cards.r.RefereeSquad.class)); - cards.add(new SetCardInfo("Refraction Elemental", 146, Rarity.RARE, mage.cards.r.RefractionElemental.class)); cards.add(new SetCardInfo("Render Inert", 123, Rarity.UNCOMMON, mage.cards.r.RenderInert.class)); cards.add(new SetCardInfo("Rona, Herald of Invasion", 295, Rarity.RARE, mage.cards.r.RonaHeraldOfInvasion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rona, Herald of Invasion", 75, Rarity.RARE, mage.cards.r.RonaHeraldOfInvasion.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rona, Tolarian Obliterator", 295, Rarity.RARE, mage.cards.r.RonaTolarianObliterator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rona, Tolarian Obliterator", 75, Rarity.RARE, mage.cards.r.RonaTolarianObliterator.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rooftop Saboteurs", 62, Rarity.UNCOMMON, mage.cards.r.RooftopSaboteurs.class)); cards.add(new SetCardInfo("Rugged Highlands", 271, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Ruins Recluse", 336, Rarity.UNCOMMON, mage.cards.r.RuinsRecluse.class)); cards.add(new SetCardInfo("Saiba Cryptomancer", 76, Rarity.COMMON, mage.cards.s.SaibaCryptomancer.class)); @@ -393,9 +342,7 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Seedpod Caretaker", 325, Rarity.UNCOMMON, mage.cards.s.SeedpodCaretaker.class)); cards.add(new SetCardInfo("Seer of Stolen Sight", 330, Rarity.UNCOMMON, mage.cards.s.SeerOfStolenSight.class)); cards.add(new SetCardInfo("Seraph of New Capenna", 36, Rarity.UNCOMMON, mage.cards.s.SeraphOfNewCapenna.class)); - cards.add(new SetCardInfo("Seraph of New Phyrexia", 36, Rarity.UNCOMMON, mage.cards.s.SeraphOfNewPhyrexia.class)); cards.add(new SetCardInfo("Serpent-Blade Assailant", 205, Rarity.COMMON, mage.cards.s.SerpentBladeAssailant.class)); - cards.add(new SetCardInfo("Serra Faithkeeper", 21, Rarity.UNCOMMON, mage.cards.s.SerraFaithkeeper.class)); cards.add(new SetCardInfo("Shatter the Source", 164, Rarity.COMMON, mage.cards.s.ShatterTheSource.class)); cards.add(new SetCardInfo("Sheoldred", 125, Rarity.MYTHIC, mage.cards.s.Sheoldred.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sheoldred", 297, Rarity.MYTHIC, mage.cards.s.Sheoldred.class, NON_FULL_USE_VARIOUS)); @@ -404,7 +351,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Sigiled Sentinel", 37, Rarity.COMMON, mage.cards.s.SigiledSentinel.class)); cards.add(new SetCardInfo("Skittering Surveyor", 264, Rarity.COMMON, mage.cards.s.SkitteringSurveyor.class)); cards.add(new SetCardInfo("Skyclave Aerialist", 78, Rarity.UNCOMMON, mage.cards.s.SkyclaveAerialist.class)); - cards.add(new SetCardInfo("Skyclave Invader", 78, Rarity.UNCOMMON, mage.cards.s.SkyclaveInvader.class)); cards.add(new SetCardInfo("Stasis Field", 79, Rarity.COMMON, mage.cards.s.StasisField.class)); cards.add(new SetCardInfo("Stoke the Flames", 166, Rarity.UNCOMMON, mage.cards.s.StokeTheFlames.class)); cards.add(new SetCardInfo("Storm the Seedcore", 206, Rarity.UNCOMMON, mage.cards.s.StormTheSeedcore.class)); @@ -427,29 +373,12 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Tandem Takedown", 208, Rarity.UNCOMMON, mage.cards.t.TandemTakedown.class)); cards.add(new SetCardInfo("Tangled Skyline", 209, Rarity.UNCOMMON, mage.cards.t.TangledSkyline.class)); cards.add(new SetCardInfo("Tarkir Duneshaper", 43, Rarity.COMMON, mage.cards.t.TarkirDuneshaper.class)); - cards.add(new SetCardInfo("Teferi Akosa of Zhalfir", 239, Rarity.MYTHIC, mage.cards.t.TeferiAkosaOfZhalfir.class)); cards.add(new SetCardInfo("Temporal Cleansing", 80, Rarity.COMMON, mage.cards.t.TemporalCleansing.class)); cards.add(new SetCardInfo("Tenured Oilcaster", 126, Rarity.COMMON, mage.cards.t.TenuredOilcaster.class)); cards.add(new SetCardInfo("Terror of Towashi", 331, Rarity.RARE, mage.cards.t.TerrorOfTowashi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Terror of Towashi", 378, Rarity.RARE, mage.cards.t.TerrorOfTowashi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia and The Gitrog Monster", 255, Rarity.MYTHIC, mage.cards.t.ThaliaAndTheGitrogMonster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalia and The Gitrog Monster", 316, Rarity.MYTHIC, mage.cards.t.ThaliaAndTheGitrogMonster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 12, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 292, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Argent Etchings", 338, Rarity.MYTHIC, mage.cards.t.TheArgentEtchings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Broken Sky", 241, Rarity.RARE, mage.cards.t.TheBrokenSky.class)); - cards.add(new SetCardInfo("The Grand Evolution", 213, Rarity.MYTHIC, mage.cards.t.TheGrandEvolution.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Grand Evolution", 301, Rarity.MYTHIC, mage.cards.t.TheGrandEvolution.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Grand Evolution", 342, Rarity.MYTHIC, mage.cards.t.TheGrandEvolution.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Synthesis", 294, Rarity.MYTHIC, mage.cards.t.TheGreatSynthesis.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Synthesis", 339, Rarity.MYTHIC, mage.cards.t.TheGreatSynthesis.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Synthesis", 65, Rarity.MYTHIC, mage.cards.t.TheGreatSynthesis.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Work", 169, Rarity.MYTHIC, mage.cards.t.TheGreatWork.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Work", 299, Rarity.MYTHIC, mage.cards.t.TheGreatWork.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Great Work", 341, Rarity.MYTHIC, mage.cards.t.TheGreatWork.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The True Scriptures", 125, Rarity.MYTHIC, mage.cards.t.TheTrueScriptures.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The True Scriptures", 297, Rarity.MYTHIC, mage.cards.t.TheTrueScriptures.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The True Scriptures", 340, Rarity.MYTHIC, mage.cards.t.TheTrueScriptures.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thornwood Falls", 274, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Thrashing Frontliner", 167, Rarity.COMMON, mage.cards.t.ThrashingFrontliner.class)); cards.add(new SetCardInfo("Thunderhead Squadron", 81, Rarity.COMMON, mage.cards.t.ThunderheadSquadron.class)); @@ -463,16 +392,13 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Traumatic Revelation", 127, Rarity.COMMON, mage.cards.t.TraumaticRevelation.class)); cards.add(new SetCardInfo("Tribute to the World Tree", 211, Rarity.RARE, mage.cards.t.TributeToTheWorldTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tribute to the World Tree", 373, Rarity.RARE, mage.cards.t.TributeToTheWorldTree.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Truga Cliffcharger", 233, Rarity.UNCOMMON, mage.cards.t.TrugaCliffcharger.class)); cards.add(new SetCardInfo("Unseal the Necropolis", 128, Rarity.COMMON, mage.cards.u.UnsealTheNecropolis.class)); cards.add(new SetCardInfo("Urabrask", 169, Rarity.MYTHIC, mage.cards.u.Urabrask.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Urabrask", 299, Rarity.MYTHIC, mage.cards.u.Urabrask.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Urabrask", 341, Rarity.MYTHIC, mage.cards.u.Urabrask.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Urn of Godfire", 266, Rarity.COMMON, mage.cards.u.UrnOfGodfire.class)); - cards.add(new SetCardInfo("Valor's Reach Tag Team", 235, Rarity.UNCOMMON, mage.cards.v.ValorsReachTagTeam.class)); cards.add(new SetCardInfo("Vanquish the Weak", 129, Rarity.COMMON, mage.cards.v.VanquishTheWeak.class)); cards.add(new SetCardInfo("Vengeant Earth", 212, Rarity.COMMON, mage.cards.v.VengeantEarth.class)); - cards.add(new SetCardInfo("Vertex Paladin", 242, Rarity.UNCOMMON, mage.cards.v.VertexPaladin.class)); cards.add(new SetCardInfo("Volcanic Spite", 170, Rarity.COMMON, mage.cards.v.VolcanicSpite.class)); cards.add(new SetCardInfo("Voldaren Thrillseeker", 171, Rarity.RARE, mage.cards.v.VoldarenThrillseeker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Voldaren Thrillseeker", 367, Rarity.RARE, mage.cards.v.VoldarenThrillseeker.class, NON_FULL_USE_VARIOUS)); @@ -485,7 +411,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Wicked Slumber", 84, Rarity.UNCOMMON, mage.cards.w.WickedSlumber.class)); cards.add(new SetCardInfo("Wildwood Escort", 216, Rarity.COMMON, mage.cards.w.WildwoodEscort.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 276, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); - cards.add(new SetCardInfo("Winnowing Forces", 236, Rarity.UNCOMMON, mage.cards.w.WinnowingForces.class)); cards.add(new SetCardInfo("Wrenn and Realmbreaker", 217, Rarity.MYTHIC, mage.cards.w.WrennAndRealmbreaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wrenn and Realmbreaker", 322, Rarity.MYTHIC, mage.cards.w.WrennAndRealmbreaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wrenn's Resolve", 173, Rarity.COMMON, mage.cards.w.WrennsResolve.class)); @@ -497,7 +422,6 @@ public final class MarchOfTheMachine extends ExpansionSet { cards.add(new SetCardInfo("Zephyr Winder", 328, Rarity.COMMON, mage.cards.z.ZephyrWinder.class)); cards.add(new SetCardInfo("Zhalfirin Lancer", 45, Rarity.UNCOMMON, mage.cards.z.ZhalfirinLancer.class)); cards.add(new SetCardInfo("Zhalfirin Shapecraft", 87, Rarity.COMMON, mage.cards.z.ZhalfirinShapecraft.class)); - cards.add(new SetCardInfo("Zilortha, Apex of Ikoria", 190, Rarity.RARE, mage.cards.z.ZilorthaApexOfIkoria.class)); cards.add(new SetCardInfo("Zimone and Dina", 257, Rarity.MYTHIC, mage.cards.z.ZimoneAndDina.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zimone and Dina", 318, Rarity.MYTHIC, mage.cards.z.ZimoneAndDina.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zurgo and Ojutai", 258, Rarity.MYTHIC, mage.cards.z.ZurgoAndOjutai.class, NON_FULL_USE_VARIOUS)); @@ -530,10 +454,10 @@ public final class MarchOfTheMachine extends ExpansionSet { .forEach(cardInfo -> inBoosterMap.put("MUL_" + cardInfo.getCardNumber(), cardInfo)); } - @Override - public BoosterCollator createCollator() { - return new MarchOfTheMachineCollator(); - } + @Override + public BoosterCollator createCollator() { + return new MarchOfTheMachineCollator(); + } } // Booster collation info from https://www.lethe.xyz/mtg/collation/mom.html @@ -609,7 +533,7 @@ class MarchOfTheMachineCollator implements BoosterCollator { AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, - AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, + AABBBCCC, AABBBCCC, AABBBCCC, AABBBCCC, AAABBCCC, AAABBCCC, AAABBCCC, AAABBCCC, AAABBCCC, AAABBCCC, AAABBCCC, AAABBBCC, AAABBBCC, AAABBBCC, AAABBBCC, AAABBBCC, @@ -626,7 +550,7 @@ class MarchOfTheMachineCollator implements BoosterCollator { private final RarityConfiguration uncommonRuns = new RarityConfiguration( RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, - RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, + RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, RuUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, URUUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, UuRUU, diff --git a/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java b/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java new file mode 100644 index 00000000000..9381ea8a8b2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/MarvelLegendsSeriesInserts.java @@ -0,0 +1,28 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * https://scryfall.com/sets/lmar + */ +public class MarvelLegendsSeriesInserts extends ExpansionSet { + + private static final MarvelLegendsSeriesInserts instance = new MarvelLegendsSeriesInserts(); + + public static MarvelLegendsSeriesInserts getInstance() { + return instance; + } + + private MarvelLegendsSeriesInserts() { + super("Marvel Legends Series Inserts", "LMAR", ExpansionSet.buildDate(2025, 9, 30), SetType.PROMOTIONAL); + this.hasBoosters = false; + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 1, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class)); + cards.add(new SetCardInfo("Huntmaster of the Fells", 3, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class)); + cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 4, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class)); + cards.add(new SetCardInfo("Spectacular Spider-Man", 2, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelSuperHeroes.java b/Mage.Sets/src/mage/sets/MarvelSuperHeroes.java new file mode 100644 index 00000000000..dd95b3dd38f --- /dev/null +++ b/Mage.Sets/src/mage/sets/MarvelSuperHeroes.java @@ -0,0 +1,39 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class MarvelSuperHeroes extends ExpansionSet { + + private static final MarvelSuperHeroes instance = new MarvelSuperHeroes(); + + public static MarvelSuperHeroes getInstance() { + return instance; + } + + private MarvelSuperHeroes() { + super("Marvel Super Heroes", "MSH", ExpansionSet.buildDate(2026, 6, 26), SetType.EXPANSION); + this.blockName = "Marvel Super Heroes"; // for sorting in GUI + this.hasBasicLands = false; // temporary + + cards.add(new SetCardInfo("Attuma, Atlantean Warlord", 47, Rarity.UNCOMMON, mage.cards.a.AttumaAtlanteanWarlord.class)); + cards.add(new SetCardInfo("Bruce Banner", 390, Rarity.MYTHIC, mage.cards.b.BruceBanner.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bruce Banner", 49, Rarity.MYTHIC, mage.cards.b.BruceBanner.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Captain America, Super-Soldier", 387, Rarity.MYTHIC, mage.cards.c.CaptainAmericaSuperSoldier.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Captain America, Super-Soldier", 9, Rarity.MYTHIC, mage.cards.c.CaptainAmericaSuperSoldier.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Doctor Doom", 394, Rarity.MYTHIC, mage.cards.d.DoctorDoom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Doctor Doom", 95, Rarity.MYTHIC, mage.cards.d.DoctorDoom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Moon Girl and Devil Dinosaur", 223, Rarity.RARE, mage.cards.m.MoonGirlAndDevilDinosaur.class)); + cards.add(new SetCardInfo("Namor the Sub-Mariner", 391, Rarity.MYTHIC, mage.cards.n.NamorTheSubMariner.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Namor the Sub-Mariner", 69, Rarity.MYTHIC, mage.cards.n.NamorTheSubMariner.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Quicksilver, Brash Blur", 148, Rarity.RARE, mage.cards.q.QuicksilverBrashBlur.class)); + cards.add(new SetCardInfo("Super-Skrull", 115, Rarity.RARE, mage.cards.s.SuperSkrull.class)); + cards.add(new SetCardInfo("The Coming of Galactus", 212, Rarity.MYTHIC, mage.cards.t.TheComingOfGalactus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Coming of Galactus", 307, Rarity.MYTHIC, mage.cards.t.TheComingOfGalactus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Sentry, Golden Guardian", 35, Rarity.RARE, mage.cards.t.TheSentryGoldenGuardian.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java b/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java new file mode 100644 index 00000000000..d66f0f251ce --- /dev/null +++ b/Mage.Sets/src/mage/sets/MarvelSuperHeroesCommander.java @@ -0,0 +1,28 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class MarvelSuperHeroesCommander extends ExpansionSet { + + private static final MarvelSuperHeroesCommander instance = new MarvelSuperHeroesCommander(); + + public static MarvelSuperHeroesCommander getInstance() { + return instance; + } + + private MarvelSuperHeroesCommander() { + super("Marvel Super Heroes Commander", "MSC", ExpansionSet.buildDate(2026, 6, 26), SetType.SUPPLEMENTAL); + this.blockName = "Marvel Super Heroes"; // for sorting in GUI + this.hasBasicLands = false; // temporary + + cards.add(new SetCardInfo("Human Torch", 3, Rarity.MYTHIC, mage.cards.h.HumanTorch.class)); + cards.add(new SetCardInfo("Invisible Woman", 1, Rarity.MYTHIC, mage.cards.i.InvisibleWoman.class)); + cards.add(new SetCardInfo("Mister Fantastic", 2, Rarity.MYTHIC, mage.cards.m.MisterFantastic.class)); + cards.add(new SetCardInfo("The Thing", 4, Rarity.MYTHIC, mage.cards.t.TheThing.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java index 6479f72823e..8f713b9a4d7 100644 --- a/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java +++ b/Mage.Sets/src/mage/sets/MarvelsSpiderMan.java @@ -4,15 +4,11 @@ import mage.cards.ExpansionSet; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.Arrays; -import java.util.List; - /** * @author TheElk801 */ public final class MarvelsSpiderMan extends ExpansionSet { - private static final List unfinished = Arrays.asList("Eddie Brock", "Gwen Stacy", "Miles Morales", "Norman Osborn", "Peter Parker"); private static final MarvelsSpiderMan instance = new MarvelsSpiderMan(); public static MarvelsSpiderMan getInstance() { @@ -40,14 +36,14 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); cards.add(new SetCardInfo("Bagel and Schmear", 161, Rarity.COMMON, mage.cards.b.BagelAndSchmear.class)); cards.add(new SetCardInfo("Beetle, Legacy Criminal", 26, Rarity.COMMON, mage.cards.b.BeetleLegacyCriminal.class)); - cards.add(new SetCardInfo("Behold the Sinister Six!", 221, Rarity.MYTHIC, mage.cards.b.BeholdTheSinisterSix.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Behold the Sinister Six!", 221, Rarity.MYTHIC, mage.cards.b.BeholdTheSinisterSix.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Behold the Sinister Six!", 51, Rarity.MYTHIC, mage.cards.b.BeholdTheSinisterSix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Biorganic Carapace", 124, Rarity.RARE, mage.cards.b.BiorganicCarapace.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Biorganic Carapace", 269, Rarity.RARE, mage.cards.b.BiorganicCarapace.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Black Cat, Cunning Thief", 222, Rarity.RARE, mage.cards.b.BlackCatCunningThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Black Cat, Cunning Thief", 222, Rarity.RARE, mage.cards.b.BlackCatCunningThief.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Black Cat, Cunning Thief", 52, Rarity.RARE, mage.cards.b.BlackCatCunningThief.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Carnage, Crimson Chaos", 125, Rarity.RARE, mage.cards.c.CarnageCrimsonChaos.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Carnage, Crimson Chaos", 227, Rarity.RARE, mage.cards.c.CarnageCrimsonChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Carnage, Crimson Chaos", 227, Rarity.RARE, mage.cards.c.CarnageCrimsonChaos.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chameleon, Master of Disguise", 27, Rarity.UNCOMMON, mage.cards.c.ChameleonMasterOfDisguise.class)); cards.add(new SetCardInfo("Cheering Crowd", 126, Rarity.RARE, mage.cards.c.CheeringCrowd.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cheering Crowd", 270, Rarity.RARE, mage.cards.c.CheeringCrowd.class, NON_FULL_USE_VARIOUS)); @@ -64,7 +60,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Doc Ock's Tentacles", 277, Rarity.RARE, mage.cards.d.DocOcksTentacles.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doc Ock, Sinister Scientist", 29, Rarity.COMMON, mage.cards.d.DocOckSinisterScientist.class)); cards.add(new SetCardInfo("Doctor Octopus, Master Planner", 128, Rarity.MYTHIC, mage.cards.d.DoctorOctopusMasterPlanner.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Doctor Octopus, Master Planner", 228, Rarity.MYTHIC, mage.cards.d.DoctorOctopusMasterPlanner.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Doctor Octopus, Master Planner", 228, Rarity.MYTHIC, mage.cards.d.DoctorOctopusMasterPlanner.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Eddie Brock", 224, Rarity.MYTHIC, mage.cards.e.EddieBrock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Eddie Brock", 233, Rarity.MYTHIC, mage.cards.e.EddieBrock.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Eddie Brock", 55, Rarity.MYTHIC, mage.cards.e.EddieBrock.class, NON_FULL_USE_VARIOUS)); @@ -124,7 +120,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Lurking Lizards", 107, Rarity.COMMON, mage.cards.l.LurkingLizards.class)); cards.add(new SetCardInfo("Madame Web, Clairvoyant", 36, Rarity.UNCOMMON, mage.cards.m.MadameWebClairvoyant.class)); cards.add(new SetCardInfo("Mary Jane Watson", 134, Rarity.RARE, mage.cards.m.MaryJaneWatson.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mary Jane Watson", 229, Rarity.RARE, mage.cards.m.MaryJaneWatson.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mary Jane Watson", 229, Rarity.RARE, mage.cards.m.MaryJaneWatson.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.class)); cards.add(new SetCardInfo("Maximum Carnage", 225, Rarity.RARE, mage.cards.m.MaximumCarnage.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Maximum Carnage", 83, Rarity.RARE, mage.cards.m.MaximumCarnage.class, NON_FULL_USE_VARIOUS)); @@ -248,7 +244,7 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("Spider-Verse", 263, Rarity.MYTHIC, mage.cards.s.SpiderVerse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spider-Verse", 93, Rarity.MYTHIC, mage.cards.s.SpiderVerse.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 152, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 230, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spider-Woman, Stunning Savior", 230, Rarity.RARE, mage.cards.s.SpiderWomanStunningSavior.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Spiders-Man, Heroic Horde", 117, Rarity.UNCOMMON, mage.cards.s.SpidersManHeroicHorde.class)); cards.add(new SetCardInfo("Spinneret and Spiderling", 264, Rarity.RARE, mage.cards.s.SpinneretAndSpiderling.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spinneret and Spiderling", 94, Rarity.RARE, mage.cards.s.SpinneretAndSpiderling.class, NON_FULL_USE_VARIOUS)); @@ -276,12 +272,12 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("The Clone Saga", 28, Rarity.RARE, mage.cards.t.TheCloneSaga.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Death of Gwen Stacy", 223, Rarity.RARE, mage.cards.t.TheDeathOfGwenStacy.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Death of Gwen Stacy", 54, Rarity.RARE, mage.cards.t.TheDeathOfGwenStacy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Soul Stone", 242, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Soul Stone", 242, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("The Soul Stone", 243, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Soul Stone", 66, Rarity.MYTHIC, mage.cards.t.TheSoulStone.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Spot's Portal", 68, Rarity.UNCOMMON, mage.cards.t.TheSpotsPortal.class)); cards.add(new SetCardInfo("The Spot, Living Portal", 153, Rarity.RARE, mage.cards.t.TheSpotLivingPortal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Spot, Living Portal", 231, Rarity.RARE, mage.cards.t.TheSpotLivingPortal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Spot, Living Portal", 231, Rarity.RARE, mage.cards.t.TheSpotLivingPortal.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class)); cards.add(new SetCardInfo("Tombstone, Career Criminal", 70, Rarity.UNCOMMON, mage.cards.t.TombstoneCareerCriminal.class)); cards.add(new SetCardInfo("Ultimate Green Goblin", 157, Rarity.RARE, mage.cards.u.UltimateGreenGoblin.class, NON_FULL_USE_VARIOUS)); @@ -310,7 +306,5 @@ public final class MarvelsSpiderMan extends ExpansionSet { cards.add(new SetCardInfo("With Great Power...", 24, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("With Great Power...", 248, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wraith, Vicious Vigilante", 160, Rarity.UNCOMMON, mage.cards.w.WraithViciousVigilante.class)); - - cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); } } diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index 6ebaf10aca6..7666dcbd557 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -177,6 +177,8 @@ public final class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Orc General", 137, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Cannoneers", 138, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Captain", 139, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Conscripts", 140, Rarity.COMMON, mage.cards.o.OrcishConscripts.class, RETRO_ART)); + cards.add(new SetCardInfo("Orcish Farmer", 141, Rarity.COMMON, mage.cards.o.OrcishFarmer.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Lumberjack", 142, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Squatters", 143, Rarity.RARE, mage.cards.o.OrcishSquatters.class, RETRO_ART)); cards.add(new SetCardInfo("Orcish Veteran", 144, Rarity.COMMON, mage.cards.o.OrcishVeteran.class, RETRO_ART)); @@ -205,7 +207,9 @@ public final class MastersEditionII extends ExpansionSet { cards.add(new SetCardInfo("Royal Decree", 31, Rarity.RARE, mage.cards.r.RoyalDecree.class, RETRO_ART)); cards.add(new SetCardInfo("Royal Trooper", 32, Rarity.COMMON, mage.cards.r.RoyalTrooper.class, RETRO_ART)); cards.add(new SetCardInfo("Ruins of Trokair", 234, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class, RETRO_ART)); + cards.add(new SetCardInfo("Sacred Boon", 33, Rarity.UNCOMMON, mage.cards.s.SacredBoon.class, RETRO_ART)); cards.add(new SetCardInfo("Savannah", 235, Rarity.RARE, mage.cards.s.Savannah.class, new CardGraphicInfo(FrameStyle.LEA_ORIGINAL_DUAL_LAND_ART_BASIC, false))); + cards.add(new SetCardInfo("Scars of the Veteran", 34, Rarity.RARE, mage.cards.s.ScarsOfTheVeteran.class, RETRO_ART)); cards.add(new SetCardInfo("Screeching Drake", 63, Rarity.COMMON, mage.cards.s.ScreechingDrake.class, RETRO_ART)); cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class, RETRO_ART)); cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class, RETRO_ART)); diff --git a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java index 1436aaf5098..823f67ae669 100644 --- a/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java +++ b/Mage.Sets/src/mage/sets/MediaAndCollaborationPromos.java @@ -24,7 +24,6 @@ public class MediaAndCollaborationPromos extends ExpansionSet { cards.add(new SetCardInfo("Ajani, Mentor of Heroes", "2024-3", Rarity.MYTHIC, mage.cards.a.AjaniMentorOfHeroes.class)); cards.add(new SetCardInfo("Ancestral Mask", "2025-2", Rarity.RARE, mage.cards.a.AncestralMask.class)); - cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", "2025-15", Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class)); cards.add(new SetCardInfo("Archangel", "2000-4", Rarity.RARE, mage.cards.a.Archangel.class, RETRO_ART)); cards.add(new SetCardInfo("Ascendant Evincar", "2000-7", Rarity.RARE, mage.cards.a.AscendantEvincar.class, RETRO_ART)); cards.add(new SetCardInfo("Avalanche Riders", "2023-5", Rarity.RARE, mage.cards.a.AvalancheRiders.class)); @@ -54,9 +53,7 @@ public class MediaAndCollaborationPromos extends ExpansionSet { cards.add(new SetCardInfo("Gush", "2024-4", Rarity.RARE, mage.cards.g.Gush.class)); cards.add(new SetCardInfo("Harald, King of Skemfar", "2021-3", Rarity.RARE, mage.cards.h.HaraldKingOfSkemfar.class)); cards.add(new SetCardInfo("Heliod's Pilgrim", "2020-6", Rarity.RARE, mage.cards.h.HeliodsPilgrim.class)); - cards.add(new SetCardInfo("Huntmaster of the Fells", "2025-17", Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class)); cards.add(new SetCardInfo("Hypnotic Sprite", "2019-5", Rarity.RARE, mage.cards.h.HypnoticSprite.class)); - cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", "2025-18", Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class)); cards.add(new SetCardInfo("Jace Beleren", "2009-1", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class)); cards.add(new SetCardInfo("Jace, Memory Adept", "2024-2", Rarity.MYTHIC, mage.cards.j.JaceMemoryAdept.class)); cards.add(new SetCardInfo("Jamuraan Lion", "1996-3", Rarity.COMMON, mage.cards.j.JamuraanLion.class, RETRO_ART)); @@ -73,7 +70,6 @@ public class MediaAndCollaborationPromos extends ExpansionSet { cards.add(new SetCardInfo("Phantasmal Dragon", "2011-1", Rarity.UNCOMMON, mage.cards.p.PhantasmalDragon.class)); cards.add(new SetCardInfo("Phyrexian Rager", "2000-5", Rarity.COMMON, mage.cards.p.PhyrexianRager.class, RETRO_ART)); cards.add(new SetCardInfo("Pyromancer's Gauntlet", "2023-6", Rarity.RARE, mage.cards.p.PyromancersGauntlet.class, RETRO_ART)); - cards.add(new SetCardInfo("Ravager of the Fells", "2025-17", Rarity.RARE, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Ruin Crab", "2023-4", Rarity.RARE, mage.cards.r.RuinCrab.class, RETRO_ART)); cards.add(new SetCardInfo("Sandbar Crocodile", "1996-1", Rarity.COMMON, mage.cards.s.SandbarCrocodile.class, RETRO_ART)); cards.add(new SetCardInfo("Scent of Cinder", "1999-1", Rarity.COMMON, mage.cards.s.ScentOfCinder.class, RETRO_ART)); @@ -85,7 +81,6 @@ public class MediaAndCollaborationPromos extends ExpansionSet { cards.add(new SetCardInfo("Shrieking Drake", "1997-2", Rarity.COMMON, mage.cards.s.ShriekingDrake.class, RETRO_ART)); cards.add(new SetCardInfo("Silver Drake", "2000-2", Rarity.COMMON, mage.cards.s.SilverDrake.class, RETRO_ART)); cards.add(new SetCardInfo("Snuff Out", "2024-1", Rarity.RARE, mage.cards.s.SnuffOut.class)); - cards.add(new SetCardInfo("Spectacular Spider-Man", "2025-16", Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class)); cards.add(new SetCardInfo("Spined Wurm", "2001-1", Rarity.COMMON, mage.cards.s.SpinedWurm.class, RETRO_ART)); cards.add(new SetCardInfo("Sprite Dragon", "2020-5", Rarity.RARE, mage.cards.s.SpriteDragon.class)); cards.add(new SetCardInfo("Staggering Insight", "2020-3", Rarity.RARE, mage.cards.s.StaggeringInsight.class)); diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index b4afbf883c7..57fe3560988 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -41,9 +41,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Aether Spike", 50, Rarity.COMMON, mage.cards.a.AetherSpike.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aether Spike", 398, Rarity.COMMON, mage.cards.a.AetherSpike.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani Fells the Godsire", 19, Rarity.UNCOMMON, mage.cards.a.AjaniFellsTheGodsire.class)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 237, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 442, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani, Nacatl Avenger", 468, Rarity.MYTHIC, mage.cards.a.AjaniNacatlAvenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 237, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 442, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ajani, Nacatl Pariah", 468, Rarity.MYTHIC, mage.cards.a.AjaniNacatlPariah.class, NON_FULL_USE_VARIOUS)); @@ -216,9 +213,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Gravedig", 96, Rarity.COMMON, mage.cards.g.Gravedig.class)); cards.add(new SetCardInfo("Grim Servant", 97, Rarity.UNCOMMON, mage.cards.g.GrimServant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grim Servant", 409, Rarity.UNCOMMON, mage.cards.g.GrimServant.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Grist, the Plague Swarm", 251, Rarity.MYTHIC, mage.cards.g.GristThePlagueSwarm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grist, the Plague Swarm", 446, Rarity.MYTHIC, mage.cards.g.GristThePlagueSwarm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grist, the Plague Swarm", 472, Rarity.MYTHIC, mage.cards.g.GristThePlagueSwarm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grist, Voracious Larva", 251, Rarity.MYTHIC, mage.cards.g.GristVoraciousLarva.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grist, Voracious Larva", 446, Rarity.MYTHIC, mage.cards.g.GristVoraciousLarva.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grist, Voracious Larva", 472, Rarity.MYTHIC, mage.cards.g.GristVoraciousLarva.class, NON_FULL_USE_VARIOUS)); @@ -384,9 +378,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Pyretic Rebirth", 200, Rarity.UNCOMMON, mage.cards.p.PyreticRebirth.class)); cards.add(new SetCardInfo("Quest for the Necropolis", 104, Rarity.UNCOMMON, mage.cards.q.QuestForTheNecropolis.class)); cards.add(new SetCardInfo("Ral and the Implicit Maze", 132, Rarity.UNCOMMON, mage.cards.r.RalAndTheImplicitMaze.class)); - cards.add(new SetCardInfo("Ral, Leyline Prodigy", 247, Rarity.MYTHIC, mage.cards.r.RalLeylineProdigy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ral, Leyline Prodigy", 445, Rarity.MYTHIC, mage.cards.r.RalLeylineProdigy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ral, Leyline Prodigy", 471, Rarity.MYTHIC, mage.cards.r.RalLeylineProdigy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ral, Monsoon Mage", 247, Rarity.MYTHIC, mage.cards.r.RalMonsoonMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ral, Monsoon Mage", 445, Rarity.MYTHIC, mage.cards.r.RalMonsoonMage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ral, Monsoon Mage", 471, Rarity.MYTHIC, mage.cards.r.RalMonsoonMage.class, NON_FULL_USE_VARIOUS)); @@ -455,9 +446,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Sorin of House Markov", 245, Rarity.MYTHIC, mage.cards.s.SorinOfHouseMarkov.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sorin of House Markov", 444, Rarity.MYTHIC, mage.cards.s.SorinOfHouseMarkov.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sorin of House Markov", 470, Rarity.MYTHIC, mage.cards.s.SorinOfHouseMarkov.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sorin, Ravenous Neonate", 245, Rarity.MYTHIC, mage.cards.s.SorinRavenousNeonate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sorin, Ravenous Neonate", 444, Rarity.MYTHIC, mage.cards.s.SorinRavenousNeonate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sorin, Ravenous Neonate", 470, Rarity.MYTHIC, mage.cards.s.SorinRavenousNeonate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sowing Mycospawn", 170, Rarity.RARE, mage.cards.s.SowingMycospawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sowing Mycospawn", 340, Rarity.RARE, mage.cards.s.SowingMycospawn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spawn-Gang Commander", 140, Rarity.UNCOMMON, mage.cards.s.SpawnGangCommander.class)); @@ -482,9 +470,6 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 443, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 469, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 242, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 443, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 469, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Temperamental Oozewagg", 172, Rarity.COMMON, mage.cards.t.TemperamentalOozewagg.class)); cards.add(new SetCardInfo("Tempest Harvester", 73, Rarity.COMMON, mage.cards.t.TempestHarvester.class)); cards.add(new SetCardInfo("Territory Culler", 173, Rarity.UNCOMMON, mage.cards.t.TerritoryCuller.class)); diff --git a/Mage.Sets/src/mage/sets/PioneerMasters.java b/Mage.Sets/src/mage/sets/PioneerMasters.java index e05c6791aa7..16d8046ec03 100644 --- a/Mage.Sets/src/mage/sets/PioneerMasters.java +++ b/Mage.Sets/src/mage/sets/PioneerMasters.java @@ -142,7 +142,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Expedite", 374, Rarity.COMMON, mage.cards.e.Expedite.class)); cards.add(new SetCardInfo("Experiment One", 173, Rarity.UNCOMMON, mage.cards.e.ExperimentOne.class)); cards.add(new SetCardInfo("Exquisite Firecraft", 133, Rarity.RARE, mage.cards.e.ExquisiteFirecraft.class)); - cards.add(new SetCardInfo("Extricator of Flesh", 12, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfFlesh.class)); cards.add(new SetCardInfo("Extricator of Sin", 12, Rarity.UNCOMMON, mage.cards.e.ExtricatorOfSin.class)); cards.add(new SetCardInfo("Fall of the Hammer", 134, Rarity.COMMON, mage.cards.f.FallOfTheHammer.class)); cards.add(new SetCardInfo("Fallaji Archaeologist", 55, Rarity.COMMON, mage.cards.f.FallajiArchaeologist.class)); @@ -167,7 +166,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Ghor-Clan Rampager", 226, Rarity.UNCOMMON, mage.cards.g.GhorClanRampager.class)); cards.add(new SetCardInfo("Ghostblade Eidolon", 13, Rarity.COMMON, mage.cards.g.GhostbladeEidolon.class)); cards.add(new SetCardInfo("Gideon, Ally of Zendikar", 14, Rarity.MYTHIC, mage.cards.g.GideonAllyOfZendikar.class)); - cards.add(new SetCardInfo("Gideon, Battle-Forged", 23, Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); cards.add(new SetCardInfo("Gift of Orzhova", 307, Rarity.UNCOMMON, mage.cards.g.GiftOfOrzhova.class)); cards.add(new SetCardInfo("Give // Take", 389, Rarity.UNCOMMON, mage.cards.g.GiveTake.class)); cards.add(new SetCardInfo("Gladecover Scout", 175, Rarity.COMMON, mage.cards.g.GladecoverScout.class)); @@ -206,7 +204,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Izzet Guildgate", 267, Rarity.COMMON, mage.cards.i.IzzetGuildgate.class)); cards.add(new SetCardInfo("Jace, Architect of Thought", 329, Rarity.MYTHIC, mage.cards.j.JaceArchitectOfThought.class)); cards.add(new SetCardInfo("Jace, Memory Adept", 330, Rarity.MYTHIC, mage.cards.j.JaceMemoryAdept.class)); - cards.add(new SetCardInfo("Jace, Telepath Unbound", 60, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 60, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); cards.add(new SetCardInfo("Jarad's Orders", 390, Rarity.RARE, mage.cards.j.JaradsOrders.class)); cards.add(new SetCardInfo("Jhessian Thief", 61, Rarity.UNCOMMON, mage.cards.j.JhessianThief.class)); @@ -232,7 +229,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Lifebane Zombie", 95, Rarity.RARE, mage.cards.l.LifebaneZombie.class)); cards.add(new SetCardInfo("Liliana of the Dark Realms", 334, Rarity.MYTHIC, mage.cards.l.LilianaOfTheDarkRealms.class)); cards.add(new SetCardInfo("Liliana Vess", 335, Rarity.MYTHIC, mage.cards.l.LilianaVess.class)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", 96, Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", 96, Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); cards.add(new SetCardInfo("Limits of Solidarity", 375, Rarity.UNCOMMON, mage.cards.l.LimitsOfSolidarity.class)); cards.add(new SetCardInfo("Linvala, the Preserver", 25, Rarity.RARE, mage.cards.l.LinvalaThePreserver.class)); @@ -266,7 +262,6 @@ public class PioneerMasters extends ExpansionSet { cards.add(new SetCardInfo("Nightveil Specter", 314, Rarity.UNCOMMON, mage.cards.n.NightveilSpecter.class)); cards.add(new SetCardInfo("Nimbus Naiad", 67, Rarity.COMMON, mage.cards.n.NimbusNaiad.class)); cards.add(new SetCardInfo("Nissa's Pilgrimage", 348, Rarity.UNCOMMON, mage.cards.n.NissasPilgrimage.class)); - cards.add(new SetCardInfo("Nissa, Sage Animist", 187, Rarity.MYTHIC, mage.cards.n.NissaSageAnimist.class)); cards.add(new SetCardInfo("Nissa, Vastwood Seer", 187, Rarity.MYTHIC, mage.cards.n.NissaVastwoodSeer.class)); cards.add(new SetCardInfo("Nissa, Voice of Zendikar", 188, Rarity.MYTHIC, mage.cards.n.NissaVoiceOfZendikar.class)); cards.add(new SetCardInfo("Nivix Cyclops", 234, Rarity.COMMON, mage.cards.n.NivixCyclops.class)); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java index 3b956af573e..03e984070f9 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalan.java @@ -45,7 +45,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Aquatic Incursion", 32, Rarity.UNCOMMON, mage.cards.a.AquaticIncursion.class)); cards.add(new SetCardInfo("Arch of Orazca", 185, Rarity.RARE, mage.cards.a.ArchOfOrazca.class)); cards.add(new SetCardInfo("Arterial Flow", 62, Rarity.UNCOMMON, mage.cards.a.ArterialFlow.class)); - cards.add(new SetCardInfo("Atzal, Cave of Eternity", 160, Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); cards.add(new SetCardInfo("Atzocan Seer", 153, Rarity.UNCOMMON, mage.cards.a.AtzocanSeer.class)); cards.add(new SetCardInfo("Awakened Amalgam", 175, Rarity.RARE, mage.cards.a.AwakenedAmalgam.class)); cards.add(new SetCardInfo("Azor's Gateway", 176, Rarity.MYTHIC, mage.cards.a.AzorsGateway.class)); @@ -110,7 +109,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Goblin Trailblazer", 105, Rarity.COMMON, mage.cards.g.GoblinTrailblazer.class)); cards.add(new SetCardInfo("Golden Demise", 73, Rarity.UNCOMMON, mage.cards.g.GoldenDemise.class)); cards.add(new SetCardInfo("Golden Guardian", 179, Rarity.RARE, mage.cards.g.GoldenGuardian.class)); - cards.add(new SetCardInfo("Gold-Forge Garrison", 179, Rarity.RARE, mage.cards.g.GoldForgeGarrison.class)); cards.add(new SetCardInfo("Grasping Scoundrel", 74, Rarity.COMMON, mage.cards.g.GraspingScoundrel.class)); cards.add(new SetCardInfo("Gruesome Fate", 75, Rarity.COMMON, mage.cards.g.GruesomeFate.class)); cards.add(new SetCardInfo("Hadana's Climb", 158, Rarity.RARE, mage.cards.h.HadanasClimb.class)); @@ -141,7 +139,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Mastermind's Acquisition", 77, Rarity.RARE, mage.cards.m.MastermindsAcquisition.class)); cards.add(new SetCardInfo("Mausoleum Harpy", 78, Rarity.UNCOMMON, mage.cards.m.MausoleumHarpy.class)); cards.add(new SetCardInfo("Merfolk Mistbinder", 164, Rarity.UNCOMMON, mage.cards.m.MerfolkMistbinder.class)); - cards.add(new SetCardInfo("Metzali, Tower of Triumph", 165, Rarity.RARE, mage.cards.m.MetzaliTowerOfTriumph.class)); cards.add(new SetCardInfo("Mist-Cloaked Herald", 43, Rarity.COMMON, mage.cards.m.MistCloakedHerald.class)); cards.add(new SetCardInfo("Moment of Craving", 79, Rarity.COMMON, mage.cards.m.MomentOfCraving.class)); cards.add(new SetCardInfo("Moment of Triumph", 15, Rarity.COMMON, mage.cards.m.MomentOfTriumph.class)); @@ -182,7 +179,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Riverwise Augur", 48, Rarity.UNCOMMON, mage.cards.r.RiverwiseAugur.class)); cards.add(new SetCardInfo("Sadistic Skymarcher", 85, Rarity.UNCOMMON, mage.cards.s.SadisticSkymarcher.class)); cards.add(new SetCardInfo("Sailor of Means", 49, Rarity.COMMON, mage.cards.s.SailorOfMeans.class)); - cards.add(new SetCardInfo("Sanctum of the Sun", 176, Rarity.MYTHIC, mage.cards.s.SanctumOfTheSun.class)); cards.add(new SetCardInfo("Sanguine Glorifier", 20, Rarity.COMMON, mage.cards.s.SanguineGlorifier.class)); cards.add(new SetCardInfo("Sea Legs", 50, Rarity.COMMON, mage.cards.s.SeaLegs.class)); cards.add(new SetCardInfo("Seafloor Oracle", 51, Rarity.RARE, mage.cards.s.SeafloorOracle.class)); @@ -227,14 +223,12 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Tilonalli's Crown", 120, Rarity.COMMON, mage.cards.t.TilonallisCrown.class)); cards.add(new SetCardInfo("Tilonalli's Summoner", 121, Rarity.RARE, mage.cards.t.TilonallisSummoner.class)); cards.add(new SetCardInfo("Timestream Navigator", 59, Rarity.MYTHIC, mage.cards.t.TimestreamNavigator.class)); - cards.add(new SetCardInfo("Tomb of the Dusk Rose", 166, Rarity.RARE, mage.cards.t.TombOfTheDuskRose.class)); cards.add(new SetCardInfo("Tomb Robber", 87, Rarity.RARE, mage.cards.t.TombRobber.class)); cards.add(new SetCardInfo("Trapjaw Tyrant", 29, Rarity.MYTHIC, mage.cards.t.TrapjawTyrant.class)); cards.add(new SetCardInfo("Traveler's Amulet", 184, Rarity.COMMON, mage.cards.t.TravelersAmulet.class)); cards.add(new SetCardInfo("Twilight Prophet", 88, Rarity.MYTHIC, mage.cards.t.TwilightProphet.class)); cards.add(new SetCardInfo("Vampire Champion", 198, Rarity.COMMON, mage.cards.v.VampireChampion.class)); cards.add(new SetCardInfo("Vampire Revenant", 89, Rarity.COMMON, mage.cards.v.VampireRevenant.class)); - cards.add(new SetCardInfo("Vault of Catlacan", 173, Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); cards.add(new SetCardInfo("Vona's Hunger", 90, Rarity.RARE, mage.cards.v.VonasHunger.class)); cards.add(new SetCardInfo("Voracious Vampire", 91, Rarity.COMMON, mage.cards.v.VoraciousVampire.class)); cards.add(new SetCardInfo("Vraska, Scheming Gorgon", 197, Rarity.MYTHIC, mage.cards.v.VraskaSchemingGorgon.class)); @@ -243,7 +237,6 @@ public final class RivalsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Warkite Marauder", 60, Rarity.RARE, mage.cards.w.WarkiteMarauder.class)); cards.add(new SetCardInfo("Waterknot", 61, Rarity.COMMON, mage.cards.w.Waterknot.class)); cards.add(new SetCardInfo("Wayward Swordtooth", 150, Rarity.RARE, mage.cards.w.WaywardSwordtooth.class)); - cards.add(new SetCardInfo("Winged Temple of Orazca", 158, Rarity.RARE, mage.cards.w.WingedTempleOfOrazca.class)); cards.add(new SetCardInfo("Woodland Stream", 191, Rarity.UNCOMMON, mage.cards.w.WoodlandStream.class)); cards.add(new SetCardInfo("World Shaper", 151, Rarity.RARE, mage.cards.w.WorldShaper.class)); cards.add(new SetCardInfo("Zacama, Primal Calamity", 174, Rarity.MYTHIC, mage.cards.z.ZacamaPrimalCalamity.class)); diff --git a/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java b/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java index 1fa372d0e88..b4271b59ac6 100644 --- a/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java +++ b/Mage.Sets/src/mage/sets/RivalsOfIxalanPromos.java @@ -25,7 +25,6 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Angrath, the Flame-Chained", "152s", Rarity.MYTHIC, mage.cards.a.AngrathTheFlameChained.class)); cards.add(new SetCardInfo("Arch of Orazca", "185p", Rarity.RARE, mage.cards.a.ArchOfOrazca.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arch of Orazca", "185s", Rarity.RARE, mage.cards.a.ArchOfOrazca.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Atzal, Cave of Eternity", "160s", Rarity.RARE, mage.cards.a.AtzalCaveOfEternity.class)); cards.add(new SetCardInfo("Awakened Amalgam", "175s", Rarity.RARE, mage.cards.a.AwakenedAmalgam.class)); cards.add(new SetCardInfo("Azor's Gateway", "176s", Rarity.MYTHIC, mage.cards.a.AzorsGateway.class)); cards.add(new SetCardInfo("Azor, the Lawbringer", "154s", Rarity.MYTHIC, mage.cards.a.AzorTheLawbringer.class)); @@ -53,7 +52,6 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Ghalta, Primal Hunger", 130, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", "130p", Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ghalta, Primal Hunger", "130s", Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gold-Forge Garrison", "179s", Rarity.RARE, mage.cards.g.GoldForgeGarrison.class)); cards.add(new SetCardInfo("Golden Guardian", "179s", Rarity.RARE, mage.cards.g.GoldenGuardian.class)); cards.add(new SetCardInfo("Hadana's Climb", "158s", Rarity.RARE, mage.cards.h.HadanasClimb.class)); cards.add(new SetCardInfo("Huatli, Radiant Champion", "159s", Rarity.MYTHIC, mage.cards.h.HuatliRadiantChampion.class)); @@ -65,7 +63,6 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Kumena, Tyrant of Orazca", "162s", Rarity.MYTHIC, mage.cards.k.KumenaTyrantOfOrazca.class)); cards.add(new SetCardInfo("Mastermind's Acquisition", "77p", Rarity.RARE, mage.cards.m.MastermindsAcquisition.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mastermind's Acquisition", "77s", Rarity.RARE, mage.cards.m.MastermindsAcquisition.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Metzali, Tower of Triumph", "165s", Rarity.RARE, mage.cards.m.MetzaliTowerOfTriumph.class)); cards.add(new SetCardInfo("Nezahal, Primal Tide", "45p", Rarity.RARE, mage.cards.n.NezahalPrimalTide.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nezahal, Primal Tide", "45s", Rarity.RARE, mage.cards.n.NezahalPrimalTide.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Paladin of Atonement", "16s", Rarity.RARE, mage.cards.p.PaladinOfAtonement.class)); @@ -80,7 +77,6 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Rekindling Phoenix", "111p", Rarity.MYTHIC, mage.cards.r.RekindlingPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rekindling Phoenix", "111s", Rarity.MYTHIC, mage.cards.r.RekindlingPhoenix.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Release to the Wind", "46s", Rarity.RARE, mage.cards.r.ReleaseToTheWind.class)); - cards.add(new SetCardInfo("Sanctum of the Sun", "176s", Rarity.MYTHIC, mage.cards.s.SanctumOfTheSun.class)); cards.add(new SetCardInfo("Seafloor Oracle", "51p", Rarity.RARE, mage.cards.s.SeafloorOracle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seafloor Oracle", "51s", Rarity.RARE, mage.cards.s.SeafloorOracle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Siegehorn Ceratops", "171p", Rarity.RARE, mage.cards.s.SiegehornCeratops.class, NON_FULL_USE_VARIOUS)); @@ -104,18 +100,15 @@ public class RivalsOfIxalanPromos extends ExpansionSet { cards.add(new SetCardInfo("Tilonalli's Summoner", "121p", Rarity.RARE, mage.cards.t.TilonallisSummoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tilonalli's Summoner", "121s", Rarity.RARE, mage.cards.t.TilonallisSummoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Timestream Navigator", "59s", Rarity.MYTHIC, mage.cards.t.TimestreamNavigator.class)); - cards.add(new SetCardInfo("Tomb of the Dusk Rose", "166s", Rarity.RARE, mage.cards.t.TombOfTheDuskRose.class)); cards.add(new SetCardInfo("Tomb Robber", "87s", Rarity.RARE, mage.cards.t.TombRobber.class)); cards.add(new SetCardInfo("Trapjaw Tyrant", "29s", Rarity.MYTHIC, mage.cards.t.TrapjawTyrant.class)); cards.add(new SetCardInfo("Twilight Prophet", "88s", Rarity.MYTHIC, mage.cards.t.TwilightProphet.class)); - cards.add(new SetCardInfo("Vault of Catlacan", "173s", Rarity.RARE, mage.cards.v.VaultOfCatlacan.class)); cards.add(new SetCardInfo("Vona's Hunger", "90p", Rarity.RARE, mage.cards.v.VonasHunger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vona's Hunger", "90s", Rarity.RARE, mage.cards.v.VonasHunger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warkite Marauder", "60p", Rarity.RARE, mage.cards.w.WarkiteMarauder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warkite Marauder", "60s", Rarity.RARE, mage.cards.w.WarkiteMarauder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wayward Swordtooth", "150p", Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wayward Swordtooth", "150s", Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Winged Temple of Orazca", "158s", Rarity.RARE, mage.cards.w.WingedTempleOfOrazca.class)); cards.add(new SetCardInfo("World Shaper", "151p", Rarity.RARE, mage.cards.w.WorldShaper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("World Shaper", "151s", Rarity.RARE, mage.cards.w.WorldShaper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zacama, Primal Calamity", "174p", Rarity.MYTHIC, mage.cards.z.ZacamaPrimalCalamity.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java b/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java index f36f6f8a0d8..53cb80d8f20 100644 --- a/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java +++ b/Mage.Sets/src/mage/sets/SanDiegoComicCon2015.java @@ -21,14 +21,9 @@ public class SanDiegoComicCon2015 extends ExpansionSet { this.hasBasicLands = false; cards.add(new SetCardInfo("Chandra, Fire of Kaladesh", 135, Rarity.MYTHIC, mage.cards.c.ChandraFireOfKaladesh.class)); - cards.add(new SetCardInfo("Chandra, Roaring Flame", 135, Rarity.MYTHIC, mage.cards.c.ChandraRoaringFlame.class)); - cards.add(new SetCardInfo("Gideon, Battle-Forged", 23, Rarity.MYTHIC, mage.cards.g.GideonBattleForged.class)); - cards.add(new SetCardInfo("Jace, Telepath Unbound", 60, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class)); cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 60, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class)); cards.add(new SetCardInfo("Kytheon, Hero of Akros", 23, Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class)); - cards.add(new SetCardInfo("Liliana, Defiant Necromancer", 106, Rarity.MYTHIC, mage.cards.l.LilianaDefiantNecromancer.class)); cards.add(new SetCardInfo("Liliana, Heretical Healer", 106, Rarity.MYTHIC, mage.cards.l.LilianaHereticalHealer.class)); cards.add(new SetCardInfo("Nissa, Vastwood Seer", 189, Rarity.MYTHIC, mage.cards.n.NissaVastwoodSeer.class)); - cards.add(new SetCardInfo("Nissa, Sage Animist", 189, Rarity.MYTHIC, mage.cards.n.NissaSageAnimist.class)); } } diff --git a/Mage.Sets/src/mage/sets/SecretLairCountdown.java b/Mage.Sets/src/mage/sets/SecretLairCountdown.java index 62c60ec020e..b66e5e1f650 100644 --- a/Mage.Sets/src/mage/sets/SecretLairCountdown.java +++ b/Mage.Sets/src/mage/sets/SecretLairCountdown.java @@ -19,36 +19,63 @@ public class SecretLairCountdown extends ExpansionSet { super("Secret Lair Countdown", "SLC", ExpansionSet.buildDate(2022, 11, 1), SetType.PROMOTIONAL); this.hasBasicLands = false; + cards.add(new SetCardInfo("Alhammarret's Archive", 27, Rarity.MYTHIC, mage.cards.a.AlhammarretsArchive.class, FULL_ART)); + cards.add(new SetCardInfo("Altar of the Brood", 1, Rarity.RARE, mage.cards.a.AltarOfTheBrood.class)); cards.add(new SetCardInfo("Arclight Phoenix", 2018, Rarity.MYTHIC, mage.cards.a.ArclightPhoenix.class)); cards.add(new SetCardInfo("Birthing Pod", 2011, Rarity.RARE, mage.cards.b.BirthingPod.class)); cards.add(new SetCardInfo("Bloodbraid Elf", 2009, Rarity.RARE, mage.cards.b.BloodbraidElf.class)); cards.add(new SetCardInfo("Bogardan Hellkite", 2006, Rarity.MYTHIC, mage.cards.b.BogardanHellkite.class)); + cards.add(new SetCardInfo("Brain Freeze", 2, Rarity.RARE, mage.cards.b.BrainFreeze.class)); cards.add(new SetCardInfo("Chrome Mox", 2003, Rarity.MYTHIC, mage.cards.c.ChromeMox.class, RETRO_ART)); + cards.add(new SetCardInfo("Crop Rotation", 3, Rarity.RARE, mage.cards.c.CropRotation.class)); cards.add(new SetCardInfo("Deathrite Shaman", 2012, Rarity.RARE, mage.cards.d.DeathriteShaman.class)); + cards.add(new SetCardInfo("Demonic Consultation", 4, Rarity.RARE, mage.cards.d.DemonicConsultation.class)); cards.add(new SetCardInfo("Dragonlord Ojutai", 2015, Rarity.MYTHIC, mage.cards.d.DragonlordOjutai.class)); + cards.add(new SetCardInfo("Eerie Ultimatum", 5, Rarity.RARE, mage.cards.e.EerieUltimatum.class)); cards.add(new SetCardInfo("Elite Spellbinder", 2021, Rarity.RARE, mage.cards.e.EliteSpellbinder.class)); cards.add(new SetCardInfo("Elspeth, Sun's Champion", 2013, Rarity.MYTHIC, mage.cards.e.ElspethSunsChampion.class, RETRO_ART)); cards.add(new SetCardInfo("Emry, Lurker of the Loch", 2019, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class)); + cards.add(new SetCardInfo("Field of the Dead", 6, Rarity.RARE, mage.cards.f.FieldOfTheDead.class)); cards.add(new SetCardInfo("Genesis", 2002, Rarity.RARE, mage.cards.g.Genesis.class)); cards.add(new SetCardInfo("Glimpse of Nature", 2004, Rarity.RARE, mage.cards.g.GlimpseOfNature.class)); + cards.add(new SetCardInfo("Gray Merchant of Asphodel", 7, Rarity.RARE, mage.cards.g.GrayMerchantOfAsphodel.class)); cards.add(new SetCardInfo("Heritage Druid", 2008, Rarity.RARE, mage.cards.h.HeritageDruid.class)); + cards.add(new SetCardInfo("Hymn to Tourach", 8, Rarity.RARE, mage.cards.h.HymnToTourach.class)); + cards.add(new SetCardInfo("Isochron Scepter", 9, Rarity.RARE, mage.cards.i.IsochronScepter.class)); + cards.add(new SetCardInfo("Junji, the Midnight Sky", 10, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class)); + cards.add(new SetCardInfo("Krark-Clan Ironworks", 11, Rarity.RARE, mage.cards.k.KrarkClanIronworks.class)); cards.add(new SetCardInfo("Lightning Helix", 2005, Rarity.RARE, mage.cards.l.LightningHelix.class)); cards.add(new SetCardInfo("Lim-Dul's Vault", 1996, Rarity.RARE, mage.cards.l.LimDulsVault.class)); cards.add(new SetCardInfo("Lin Sivvi, Defiant Hero", 2000, Rarity.RARE, mage.cards.l.LinSivviDefiantHero.class)); + cards.add(new SetCardInfo("Llanowar Elves", 12, Rarity.RARE, mage.cards.l.LlanowarElves.class)); cards.add(new SetCardInfo("Lotus Field", 2023, Rarity.MYTHIC, mage.cards.l.LotusField.class)); cards.add(new SetCardInfo("Mishra's Factory", 1994, Rarity.RARE, mage.cards.m.MishrasFactory.class)); + cards.add(new SetCardInfo("Myrel, Shield of Argive", 13, Rarity.RARE, mage.cards.m.MyrelShieldOfArgive.class)); + cards.add(new SetCardInfo("Narset's Reversal", 14, Rarity.RARE, mage.cards.n.NarsetsReversal.class)); cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 2022, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class)); cards.add(new SetCardInfo("Necropotence", 1995, Rarity.MYTHIC, mage.cards.n.Necropotence.class)); cards.add(new SetCardInfo("Nicol Bolas, God-Pharaoh", 2017, Rarity.MYTHIC, mage.cards.n.NicolBolasGodPharaoh.class)); + cards.add(new SetCardInfo("Ob Nixilis, the Fallen", 15, Rarity.MYTHIC, mage.cards.o.ObNixilisTheFallen.class)); + cards.add(new SetCardInfo("Phyrexian Altar", 16, Rarity.RARE, mage.cards.p.PhyrexianAltar.class)); cards.add(new SetCardInfo("Ponder", 2007, Rarity.RARE, mage.cards.p.Ponder.class)); - cards.add(new SetCardInfo("Shark Typhoon", 2020, Rarity.RARE, mage.cards.s.SharkTyphoon.class)); + cards.add(new SetCardInfo("Questing Beast", 17, Rarity.MYTHIC, mage.cards.q.QuestingBeast.class)); + cards.add(new SetCardInfo("Retrofitter Foundry", 18, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); + cards.add(new SetCardInfo("Shark Typhoon", 2020, Rarity.RARE, mage.cards.s.SharkTyphoon.class, FULL_ART)); cards.add(new SetCardInfo("Shivan Dragon", 1993, Rarity.RARE, mage.cards.s.ShivanDragon.class)); cards.add(new SetCardInfo("Siege Rhino", 2014, Rarity.RARE, mage.cards.s.SiegeRhino.class)); cards.add(new SetCardInfo("Smokestack", 1998, Rarity.RARE, mage.cards.s.Smokestack.class)); + cards.add(new SetCardInfo("Sol Ring", 19, Rarity.RARE, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Squee, Goblin Nabob", 1999, Rarity.RARE, mage.cards.s.SqueeGoblinNabob.class)); cards.add(new SetCardInfo("Sun Titan", 2010, Rarity.MYTHIC, mage.cards.s.SunTitan.class)); + cards.add(new SetCardInfo("Temple of the False God", 20, Rarity.RARE, mage.cards.t.TempleOfTheFalseGod.class)); cards.add(new SetCardInfo("Thalia, Heretic Cathar", 2016, Rarity.RARE, mage.cards.t.ThaliaHereticCathar.class)); cards.add(new SetCardInfo("Tradewind Rider", 1997, Rarity.RARE, mage.cards.t.TradewindRider.class)); + cards.add(new SetCardInfo("Urza's Saga", 21, Rarity.RARE, mage.cards.u.UrzasSaga.class)); + cards.add(new SetCardInfo("Vesuva", 22, Rarity.RARE, mage.cards.v.Vesuva.class)); + cards.add(new SetCardInfo("Wasteland", 23, Rarity.RARE, mage.cards.w.Wasteland.class)); cards.add(new SetCardInfo("Wild Mongrel", 2001, Rarity.RARE, mage.cards.w.WildMongrel.class)); + cards.add(new SetCardInfo("Xantcha, Sleeper Agent", 24, Rarity.RARE, mage.cards.x.XantchaSleeperAgent.class)); + cards.add(new SetCardInfo("Yarok, the Desecrated", 25, Rarity.MYTHIC, mage.cards.y.YarokTheDesecrated.class)); + cards.add(new SetCardInfo("Zo-Zu the Punisher", 26, Rarity.RARE, mage.cards.z.ZoZuThePunisher.class)); } } diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java index 9c46db38472..bb95ee1e5a5 100644 --- a/Mage.Sets/src/mage/sets/SecretLairDrop.java +++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java @@ -262,7 +262,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Kaya, Ghost Assassin", 247, Rarity.MYTHIC, mage.cards.k.KayaGhostAssassin.class)); cards.add(new SetCardInfo("Teferi, Hero of Dominaria", 248, Rarity.MYTHIC, mage.cards.t.TeferiHeroOfDominaria.class)); cards.add(new SetCardInfo("Sol Ring", 249, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Path of Ancestry", 250, Rarity.RARE, mage.cards.p.PathOfAncestry.class)); + cards.add(new SetCardInfo("Path of Ancestry", 250, Rarity.RARE, mage.cards.p.PathOfAncestry.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dack Fayden", 251, Rarity.MYTHIC, mage.cards.d.DackFayden.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi, Time Raveler", 252, Rarity.RARE, mage.cards.t.TeferiTimeRaveler.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Karn, the Great Creator", 253, Rarity.RARE, mage.cards.k.KarnTheGreatCreator.class, RETRO_ART_USE_VARIOUS)); @@ -367,13 +367,13 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 362, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 363, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swords to Plowshares", 364, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grim Tutor", 365, Rarity.MYTHIC, mage.cards.g.GrimTutor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Blood Moon", 366, Rarity.RARE, mage.cards.b.BloodMoon.class)); + cards.add(new SetCardInfo("Grim Tutor", 365, Rarity.MYTHIC, mage.cards.g.GrimTutor.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Blood Moon", 366, Rarity.RARE, mage.cards.b.BloodMoon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cut // Ribbons", 367, Rarity.RARE, mage.cards.c.CutRibbons.class)); cards.add(new SetCardInfo("Teferi's Puzzle Box", 368, Rarity.RARE, mage.cards.t.TeferisPuzzleBox.class)); cards.add(new SetCardInfo("Generous Gift", 369, Rarity.RARE, mage.cards.g.GenerousGift.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chain Lightning", 370, Rarity.RARE, mage.cards.c.ChainLightning.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kodama's Reach", 371, Rarity.RARE, mage.cards.k.KodamasReach.class)); + cards.add(new SetCardInfo("Kodama's Reach", 371, Rarity.RARE, mage.cards.k.KodamasReach.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heirloom Blade", 372, Rarity.RARE, mage.cards.h.HeirloomBlade.class)); cards.add(new SetCardInfo("Mulldrifter", 373, Rarity.RARE, mage.cards.m.Mulldrifter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mulldrifter", 374, Rarity.RARE, mage.cards.m.Mulldrifter.class, NON_FULL_USE_VARIOUS)); @@ -507,7 +507,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Kozilek, the Great Distortion", 493, Rarity.MYTHIC, mage.cards.k.KozilekTheGreatDistortion.class)); cards.add(new SetCardInfo("Primeval Titan", 494, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Huntmaster of the Fells", 495, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 495, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Platinum Angel", 496, Rarity.RARE, mage.cards.p.PlatinumAngel.class)); cards.add(new SetCardInfo("Brimaz, King of Oreskos", 497, Rarity.MYTHIC, mage.cards.b.BrimazKingOfOreskos.class)); cards.add(new SetCardInfo("Arcanis the Omnipotent", 498, Rarity.RARE, mage.cards.a.ArcanisTheOmnipotent.class)); @@ -617,7 +616,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Rogue's Passage", 607, Rarity.RARE, mage.cards.r.RoguesPassage.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("Bonescythe Sliver", 610, Rarity.RARE, mage.cards.b.BonescytheSliver.class)); cards.add(new SetCardInfo("Constricting Sliver", 611, Rarity.RARE, mage.cards.c.ConstrictingSliver.class)); cards.add(new SetCardInfo("Essence Sliver", 612, Rarity.RARE, mage.cards.e.EssenceSliver.class)); @@ -706,7 +704,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Dakkon Blackblade", 698, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", 699, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Huntmaster of the Fells", 700, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ravager of the Fells", 700, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Elspeth, Knight-Errant", 701, Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wastes", 704, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Wastes", 705, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS)); @@ -726,7 +723,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Thought-Knot Seer", 720, Rarity.RARE, mage.cards.t.ThoughtKnotSeer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Diabolic Tutor", 721, Rarity.RARE, mage.cards.d.DiabolicTutor.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Delver of Secrets", 722, Rarity.RARE, mage.cards.d.DelverOfSecrets.class)); - cards.add(new SetCardInfo("Insectile Aberration", 722, Rarity.RARE, mage.cards.i.InsectileAberration.class)); cards.add(new SetCardInfo("Brainstorm", 723, Rarity.RARE, mage.cards.b.Brainstorm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Strike", 724, Rarity.RARE, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Fleshbag Marauder", 725, Rarity.RARE, mage.cards.f.FleshbagMarauder.class, NON_FULL_USE_VARIOUS)); @@ -744,23 +740,23 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Mountain Goat", 737, Rarity.RARE, mage.cards.m.MountainGoat.class)); cards.add(new SetCardInfo("Woodland Cemetery", 738, Rarity.RARE, mage.cards.w.WoodlandCemetery.class)); cards.add(new SetCardInfo("Isolated Chapel", 739, Rarity.RARE, mage.cards.i.IsolatedChapel.class)); - cards.add(new SetCardInfo("Colossal Dreadmaw", 740, Rarity.RARE, mage.cards.c.ColossalDreadmaw.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Colossal Dreadmaw", "740*", Rarity.RARE, mage.cards.c.ColossalDreadmaw.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Colossal Dreadmaw", 740, Rarity.RARE, mage.cards.c.ColossalDreadmaw.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Colossal Dreadmaw", "740*", Rarity.RARE, mage.cards.c.ColossalDreadmaw.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos Warp", 741, Rarity.RARE, mage.cards.c.ChaosWarp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos Warp", "741*", Rarity.RARE, mage.cards.c.ChaosWarp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Command Tower", 744, Rarity.RARE, mage.cards.c.CommandTower.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani Goldmane", 745, Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani Goldmane", "745b", Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace Beleren", 746, Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace Beleren", "746b", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Liliana Vess", 747, Rarity.MYTHIC, mage.cards.l.LilianaVess.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Liliana Vess", "747b", Rarity.MYTHIC, mage.cards.l.LilianaVess.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chandra Nalaar", 748, Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chandra Nalaar", "748b", Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Garruk Wildspeaker", 749, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Garruk Wildspeaker", "749b", Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Terror", 750, Rarity.RARE, mage.cards.t.Terror.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Terror", "750b", Rarity.RARE, mage.cards.t.Terror.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ajani Goldmane", 745, Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ajani Goldmane", "745b", Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace Beleren", 746, Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace Beleren", "746b", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana Vess", 747, Rarity.MYTHIC, mage.cards.l.LilianaVess.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana Vess", "747b", Rarity.MYTHIC, mage.cards.l.LilianaVess.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chandra Nalaar", 748, Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chandra Nalaar", "748b", Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Garruk Wildspeaker", 749, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Garruk Wildspeaker", "749b", Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Terror", 750, Rarity.RARE, mage.cards.t.Terror.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Terror", "750b", Rarity.RARE, mage.cards.t.Terror.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Relentless Rats", 752, Rarity.RARE, mage.cards.r.RelentlessRats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Relentless Rats", 754, Rarity.RARE, mage.cards.r.RelentlessRats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Relentless Rats", 755, Rarity.RARE, mage.cards.r.RelentlessRats.class, NON_FULL_USE_VARIOUS)); @@ -801,10 +797,10 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Wastes", "795*", Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mana Vault", "796*", Rarity.MYTHIC, mage.cards.m.ManaVault.class)); cards.add(new SetCardInfo("Seraph Sanctuary", 797, Rarity.RARE, mage.cards.s.SeraphSanctuary.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Coveted Jewel", 799, Rarity.RARE, mage.cards.c.CovetedJewel.class)); + cards.add(new SetCardInfo("Coveted Jewel", 799, Rarity.RARE, mage.cards.c.CovetedJewel.class, FULL_ART)); cards.add(new SetCardInfo("Llanowar Elves", 800, Rarity.RARE, mage.cards.l.LlanowarElves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spiteful Prankster", 801, Rarity.RARE, mage.cards.s.SpitefulPrankster.class)); - cards.add(new SetCardInfo("Haystack", 802, Rarity.RARE, mage.cards.h.Haystack.class)); + cards.add(new SetCardInfo("Haystack", 802, Rarity.RARE, mage.cards.h.Haystack.class, FULL_ART)); cards.add(new SetCardInfo("Sonic Screwdriver", 803, Rarity.RARE, mage.cards.s.SonicScrewdriver.class)); cards.add(new SetCardInfo("Beloved Princess", 804, Rarity.RARE, mage.cards.b.BelovedPrincess.class)); cards.add(new SetCardInfo("Elvish Mystic", 805, Rarity.RARE, mage.cards.e.ElvishMystic.class, NON_FULL_USE_VARIOUS)); @@ -878,10 +874,10 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 879, Rarity.MYTHIC, mage.cards.m.MinscBooTimelessHeroes.class)); cards.add(new SetCardInfo("Stuffy Doll", 880, Rarity.RARE, mage.cards.s.StuffyDoll.class)); cards.add(new SetCardInfo("Silence", 881, Rarity.RARE, mage.cards.s.Silence.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Winds of Abandon", 882, Rarity.RARE, mage.cards.w.WindsOfAbandon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Culling the Weak", 883, Rarity.RARE, mage.cards.c.CullingTheWeak.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fatal Push", 884, Rarity.RARE, mage.cards.f.FatalPush.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Young Wolf", 885, Rarity.RARE, mage.cards.y.YoungWolf.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Winds of Abandon", 882, Rarity.RARE, mage.cards.w.WindsOfAbandon.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Culling the Weak", 883, Rarity.RARE, mage.cards.c.CullingTheWeak.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Fatal Push", 884, Rarity.RARE, mage.cards.f.FatalPush.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Young Wolf", 885, Rarity.RARE, mage.cards.y.YoungWolf.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Solve the Equation", 886, Rarity.RARE, mage.cards.s.SolveTheEquation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Enduring Ideal", 887, Rarity.RARE, mage.cards.e.EnduringIdeal.class)); cards.add(new SetCardInfo("Plains", 888, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); @@ -895,13 +891,15 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("The Scarab God", 900, Rarity.MYTHIC, mage.cards.t.TheScarabGod.class, FULL_ART)); cards.add(new SetCardInfo("Lightning Bolt", 901, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Deadeye Navigator", 902, Rarity.RARE, mage.cards.d.DeadeyeNavigator.class)); - cards.add(new SetCardInfo("The Locust God", 903, Rarity.MYTHIC, mage.cards.t.TheLocustGod.class)); + cards.add(new SetCardInfo("The Locust God", 903, Rarity.MYTHIC, mage.cards.t.TheLocustGod.class, FULL_ART)); cards.add(new SetCardInfo("The Scorpion God", 904, Rarity.MYTHIC, mage.cards.t.TheScorpionGod.class)); + cards.add(new SetCardInfo("Cryptic Command", 905, Rarity.RARE, mage.cards.c.CrypticCommand.class, FULL_ART)); cards.add(new SetCardInfo("Ignoble Hierarch", 906, Rarity.RARE, mage.cards.i.IgnobleHierarch.class, FULL_ART)); cards.add(new SetCardInfo("Seedborn Muse", 907, Rarity.RARE, mage.cards.s.SeedbornMuse.class)); cards.add(new SetCardInfo("Arcane Signet", 908, Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gilded Lotus", 909, Rarity.RARE, mage.cards.g.GildedLotus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sol Ring", 910, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Path of Ancestry", 914, Rarity.RARE, mage.cards.p.PathOfAncestry.class, NON_FULL_USE_VARIOUS)); } private void addPart2() { @@ -1024,13 +1022,13 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Doomsday", 1115, Rarity.RARE, mage.cards.d.Doomsday.class)); cards.add(new SetCardInfo("Plaguecrafter", 1116, Rarity.RARE, mage.cards.p.Plaguecrafter.class)); cards.add(new SetCardInfo("Thoughtseize", 1117, Rarity.RARE, mage.cards.t.Thoughtseize.class)); - cards.add(new SetCardInfo("Ulamog, the Ceaseless Hunger", 1122, Rarity.MYTHIC, mage.cards.u.UlamogTheCeaselessHunger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ulamog, the Ceaseless Hunger", "1122b", Rarity.MYTHIC, mage.cards.u.UlamogTheCeaselessHunger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Storm", 1123, Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Storm", "1123b", Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", 1124, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ghalta, Primal Hunger", "1124b", Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Serra Ascendant", 1125, Rarity.RARE, mage.cards.s.SerraAscendant.class)); + cards.add(new SetCardInfo("Ulamog, the Ceaseless Hunger", 1122, Rarity.MYTHIC, mage.cards.u.UlamogTheCeaselessHunger.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ulamog, the Ceaseless Hunger", "1122b", Rarity.MYTHIC, mage.cards.u.UlamogTheCeaselessHunger.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Etali, Primal Storm", 1123, Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Etali, Primal Storm", "1123b", Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 1124, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", "1124b", Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Serra Ascendant", 1125, Rarity.RARE, mage.cards.s.SerraAscendant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rapid Hybridization", 1126, Rarity.RARE, mage.cards.r.RapidHybridization.class)); cards.add(new SetCardInfo("Demonic Consultation", 1127, Rarity.RARE, mage.cards.d.DemonicConsultation.class)); cards.add(new SetCardInfo("Winds of Change", 1128, Rarity.RARE, mage.cards.w.WindsOfChange.class)); @@ -1061,13 +1059,9 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Eldrazi Temple", 1154, Rarity.RARE, mage.cards.e.EldraziTemple.class)); cards.add(new SetCardInfo("Esika, God of the Tree", 1155, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", 1156, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1156, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 1157, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 1157, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 1159, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 1159, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Emrakul, the Promised End", 1160, Rarity.MYTHIC, mage.cards.e.EmrakulThePromisedEnd.class)); cards.add(new SetCardInfo("Serra Angel", 1161, Rarity.RARE, mage.cards.s.SerraAngel.class)); cards.add(new SetCardInfo("Brainstorm", 1162, Rarity.RARE, mage.cards.b.Brainstorm.class, NON_FULL_USE_VARIOUS)); @@ -1118,13 +1112,9 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Inkmoth Nexus", 1207, Rarity.RARE, mage.cards.i.InkmothNexus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Esika, God of the Tree", 1208, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", 1209, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 1209, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodline Keeper", 1210, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lord of Lineage", 1210, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nicol Bolas, the Arisen", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheArisen.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Westvale Abbey", 1212, Rarity.RARE, mage.cards.w.WestvaleAbbey.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 1212, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Phyrexian Unlife", 1213, Rarity.RARE, mage.cards.p.PhyrexianUnlife.class)); cards.add(new SetCardInfo("Phyrexian Crusader", 1214, Rarity.RARE, mage.cards.p.PhyrexianCrusader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plague Engineer", 1215, Rarity.RARE, mage.cards.p.PlagueEngineer.class)); @@ -1154,7 +1144,6 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Evin, Waterdeep Opportunist", 1239, Rarity.RARE, mage.cards.e.EvinWaterdeepOpportunist.class)); cards.add(new SetCardInfo("Jurin, Leading the Charge", 1240, Rarity.RARE, mage.cards.j.JurinLeadingTheCharge.class)); cards.add(new SetCardInfo("Casal, Lurkwood Pathfinder", 1241, Rarity.RARE, mage.cards.c.CasalLurkwoodPathfinder.class)); - cards.add(new SetCardInfo("Casal, Pathbreaker Owlbear", 1241, Rarity.RARE, mage.cards.c.CasalPathbreakerOwlbear.class)); cards.add(new SetCardInfo("Bohn, Beguiling Balladeer", 1242, Rarity.RARE, mage.cards.b.BohnBeguilingBalladeer.class)); cards.add(new SetCardInfo("Ugin, the Ineffable", 1243, Rarity.RARE, mage.cards.u.UginTheIneffable.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sorin, Imperious Bloodlord", 1244, Rarity.MYTHIC, mage.cards.s.SorinImperiousBloodlord.class)); @@ -1220,16 +1209,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Shared Summons", 1308, Rarity.RARE, mage.cards.s.SharedSummons.class)); cards.add(new SetCardInfo("Sylvan Offering", 1309, Rarity.RARE, mage.cards.s.SylvanOffering.class)); cards.add(new SetCardInfo("Sliver Legion", 1310, Rarity.MYTHIC, mage.cards.s.SliverLegion.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Lackey", 1311, Rarity.RARE, mage.cards.g.GoblinLackey.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Lackey", "1311*", Rarity.RARE, mage.cards.g.GoblinLackey.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Matron", 1312, Rarity.RARE, mage.cards.g.GoblinMatron.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Matron", "1312*", Rarity.RARE, mage.cards.g.GoblinMatron.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Recruiter", 1313, Rarity.RARE, mage.cards.g.GoblinRecruiter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Goblin Recruiter", "1313*", Rarity.RARE, mage.cards.g.GoblinRecruiter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Muxus, Goblin Grandee", 1314, Rarity.RARE, mage.cards.m.MuxusGoblinGrandee.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Muxus, Goblin Grandee", "1314*", Rarity.RARE, mage.cards.m.MuxusGoblinGrandee.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shattergang Brothers", 1315, Rarity.MYTHIC, mage.cards.s.ShattergangBrothers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shattergang Brothers", "1315*", Rarity.MYTHIC, mage.cards.s.ShattergangBrothers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Lackey", 1311, Rarity.RARE, mage.cards.g.GoblinLackey.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Lackey", "1311*", Rarity.RARE, mage.cards.g.GoblinLackey.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Matron", 1312, Rarity.RARE, mage.cards.g.GoblinMatron.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Matron", "1312*", Rarity.RARE, mage.cards.g.GoblinMatron.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Recruiter", 1313, Rarity.RARE, mage.cards.g.GoblinRecruiter.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Recruiter", "1313*", Rarity.RARE, mage.cards.g.GoblinRecruiter.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Muxus, Goblin Grandee", 1314, Rarity.RARE, mage.cards.m.MuxusGoblinGrandee.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Muxus, Goblin Grandee", "1314*", Rarity.RARE, mage.cards.m.MuxusGoblinGrandee.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Shattergang Brothers", 1315, Rarity.MYTHIC, mage.cards.s.ShattergangBrothers.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Shattergang Brothers", "1315*", Rarity.MYTHIC, mage.cards.s.ShattergangBrothers.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Nirkana Revenant", 1316, Rarity.MYTHIC, mage.cards.n.NirkanaRevenant.class)); cards.add(new SetCardInfo("Arbor Elf", 1317, Rarity.RARE, mage.cards.a.ArborElf.class)); cards.add(new SetCardInfo("Terastodon", 1318, Rarity.RARE, mage.cards.t.Terastodon.class)); @@ -1247,11 +1236,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Estrid, the Masked", "1327b", Rarity.MYTHIC, mage.cards.e.EstridTheMasked.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Tuvasa the Sunlit", 1328, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Tuvasa the Sunlit", "1328b", Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class, FULL_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Gargos, Vicious Watcher", 1329, Rarity.RARE, mage.cards.g.GargosViciousWatcher.class)); - cards.add(new SetCardInfo("Primordial Hydra", 1330, Rarity.MYTHIC, mage.cards.p.PrimordialHydra.class)); - cards.add(new SetCardInfo("Unbound Flourishing", 1331, Rarity.MYTHIC, mage.cards.u.UnboundFlourishing.class)); - cards.add(new SetCardInfo("Hydroid Krasis", 1332, Rarity.RARE, mage.cards.h.HydroidKrasis.class)); - cards.add(new SetCardInfo("Zaxara, the Exemplary", 1333, Rarity.MYTHIC, mage.cards.z.ZaxaraTheExemplary.class)); + cards.add(new SetCardInfo("Gargos, Vicious Watcher", 1329, Rarity.RARE, mage.cards.g.GargosViciousWatcher.class, FULL_ART)); + cards.add(new SetCardInfo("Primordial Hydra", 1330, Rarity.MYTHIC, mage.cards.p.PrimordialHydra.class, FULL_ART)); + cards.add(new SetCardInfo("Unbound Flourishing", 1331, Rarity.MYTHIC, mage.cards.u.UnboundFlourishing.class, FULL_ART)); + cards.add(new SetCardInfo("Hydroid Krasis", 1332, Rarity.RARE, mage.cards.h.HydroidKrasis.class, FULL_ART)); + cards.add(new SetCardInfo("Zaxara, the Exemplary", 1333, Rarity.MYTHIC, mage.cards.z.ZaxaraTheExemplary.class, FULL_ART)); cards.add(new SetCardInfo("Gisela, the Broken Blade", 1335, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "1336b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bruna, the Fading Light", 1336, Rarity.RARE, mage.cards.b.BrunaTheFadingLight.class, NON_FULL_USE_VARIOUS)); @@ -1283,10 +1272,10 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 1365, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 1366, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 1367, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rewind", 1368, Rarity.RARE, mage.cards.r.Rewind.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Food Chain", 1369, Rarity.MYTHIC, mage.cards.f.FoodChain.class)); - cards.add(new SetCardInfo("Rampant Growth", 1370, Rarity.RARE, mage.cards.r.RampantGrowth.class)); - cards.add(new SetCardInfo("The First Sliver", 1371, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class)); + cards.add(new SetCardInfo("Rewind", 1368, Rarity.RARE, mage.cards.r.Rewind.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Food Chain", 1369, Rarity.MYTHIC, mage.cards.f.FoodChain.class, FULL_ART)); + cards.add(new SetCardInfo("Rampant Growth", 1370, Rarity.RARE, mage.cards.r.RampantGrowth.class, FULL_ART)); + cards.add(new SetCardInfo("The First Sliver", 1371, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class, FULL_ART)); cards.add(new SetCardInfo("Concealed Courtyard", 1372, Rarity.RARE, mage.cards.c.ConcealedCourtyard.class)); cards.add(new SetCardInfo("Spirebluff Canal", 1373, Rarity.RARE, mage.cards.s.SpirebluffCanal.class)); cards.add(new SetCardInfo("Blooming Marsh", 1374, Rarity.RARE, mage.cards.b.BloomingMarsh.class)); @@ -1305,16 +1294,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Gisela, the Broken Blade", 1387, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brisela, Voice of Nightmares", "1388b", Rarity.MYTHIC, mage.cards.b.BriselaVoiceOfNightmares.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bruna, the Fading Light", 1388, Rarity.RARE, mage.cards.b.BrunaTheFadingLight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Storm", 1389, Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Etali, Primal Storm", "1389*", Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rampaging Ferocidon", 1390, Rarity.RARE, mage.cards.r.RampagingFerocidon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rampaging Ferocidon", "1390*", Rarity.RARE, mage.cards.r.RampagingFerocidon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polyraptor", 1391, Rarity.MYTHIC, mage.cards.p.Polyraptor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polyraptor", "1391*", Rarity.MYTHIC, mage.cards.p.Polyraptor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wayward Swordtooth", 1392, Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wayward Swordtooth", "1392*", Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Regisaur Alpha", 1393, Rarity.RARE, mage.cards.r.RegisaurAlpha.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Regisaur Alpha", "1393*", Rarity.RARE, mage.cards.r.RegisaurAlpha.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Etali, Primal Storm", 1389, Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Etali, Primal Storm", "1389*", Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Rampaging Ferocidon", 1390, Rarity.RARE, mage.cards.r.RampagingFerocidon.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Rampaging Ferocidon", "1390*", Rarity.RARE, mage.cards.r.RampagingFerocidon.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Polyraptor", 1391, Rarity.MYTHIC, mage.cards.p.Polyraptor.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Polyraptor", "1391*", Rarity.MYTHIC, mage.cards.p.Polyraptor.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Wayward Swordtooth", 1392, Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Wayward Swordtooth", "1392*", Rarity.RARE, mage.cards.w.WaywardSwordtooth.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Regisaur Alpha", 1393, Rarity.RARE, mage.cards.r.RegisaurAlpha.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Regisaur Alpha", "1393*", Rarity.RARE, mage.cards.r.RegisaurAlpha.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Laboratory Maniac", 1394, Rarity.RARE, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Laboratory Maniac", "1394*", Rarity.RARE, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tasha's Hideous Laughter", 1395, Rarity.RARE, mage.cards.t.TashasHideousLaughter.class, NON_FULL_USE_VARIOUS)); @@ -1343,11 +1332,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Kumena, Tyrant of Orazca", "1412*", Rarity.MYTHIC, mage.cards.k.KumenaTyrantOfOrazca.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vona, Butcher of Magan", 1413, Rarity.MYTHIC, mage.cards.v.VonaButcherOfMagan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vona, Butcher of Magan", "1413*", Rarity.MYTHIC, mage.cards.v.VonaButcherOfMagan.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Eldritch Evolution", 1414, Rarity.RARE, mage.cards.e.EldritchEvolution.class)); - cards.add(new SetCardInfo("Giant Adephage", 1415, Rarity.MYTHIC, mage.cards.g.GiantAdephage.class)); - cards.add(new SetCardInfo("Noxious Revival", 1416, Rarity.RARE, mage.cards.n.NoxiousRevival.class)); - cards.add(new SetCardInfo("Grist, the Hunger Tide", 1417, Rarity.MYTHIC, mage.cards.g.GristTheHungerTide.class)); - cards.add(new SetCardInfo("Mazirek, Kraul Death Priest", 1418, Rarity.RARE, mage.cards.m.MazirekKraulDeathPriest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eldritch Evolution", 1414, Rarity.RARE, mage.cards.e.EldritchEvolution.class, FULL_ART)); + cards.add(new SetCardInfo("Giant Adephage", 1415, Rarity.MYTHIC, mage.cards.g.GiantAdephage.class, FULL_ART)); + cards.add(new SetCardInfo("Noxious Revival", 1416, Rarity.RARE, mage.cards.n.NoxiousRevival.class, FULL_ART)); + cards.add(new SetCardInfo("Grist, the Hunger Tide", 1417, Rarity.MYTHIC, mage.cards.g.GristTheHungerTide.class, FULL_ART)); + cards.add(new SetCardInfo("Mazirek, Kraul Death Priest", 1418, Rarity.RARE, mage.cards.m.MazirekKraulDeathPriest.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Karn, Scion of Urza", 1419, Rarity.MYTHIC, mage.cards.k.KarnScionOfUrza.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Karn, Scion of Urza", "1419*", Rarity.MYTHIC, mage.cards.k.KarnScionOfUrza.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chandra, Flame's Catalyst", 1420, Rarity.MYTHIC, mage.cards.c.ChandraFlamesCatalyst.class, NON_FULL_USE_VARIOUS)); @@ -1381,26 +1370,26 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Brion Stoutarm", 1450, Rarity.RARE, mage.cards.b.BrionStoutarm.class)); cards.add(new SetCardInfo("Samut, Voice of Dissent", 1451, Rarity.MYTHIC, mage.cards.s.SamutVoiceOfDissent.class)); cards.add(new SetCardInfo("Marchesa, the Black Rose", 1452, Rarity.RARE, mage.cards.m.MarchesaTheBlackRose.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani Goldmane", 1453, Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ajani Goldmane", "1453b", Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace Beleren", 1454, Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace Beleren", "1454b", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Liliana Vess", 1455, Rarity.MYTHIC, mage.cards.l.LilianaVess.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Liliana Vess", "1455b", Rarity.MYTHIC, mage.cards.l.LilianaVess.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chandra Nalaar", 1456, Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chandra Nalaar", "1456b", Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Garruk Wildspeaker", 1457, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Garruk Wildspeaker", "1457b", Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Death Baron", 1458, Rarity.RARE, mage.cards.d.DeathBaron.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Death Baron", "1458b", Rarity.RARE, mage.cards.d.DeathBaron.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Noxious Ghoul", 1459, Rarity.RARE, mage.cards.n.NoxiousGhoul.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Noxious Ghoul", "1459b", Rarity.RARE, mage.cards.n.NoxiousGhoul.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zombie Master", 1460, Rarity.RARE, mage.cards.z.ZombieMaster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Zombie Master", "1460b", Rarity.RARE, mage.cards.z.ZombieMaster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grimgrin, Corpse-Born", 1461, Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Grimgrin, Corpse-Born", "1461b", Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Unholy Grotto", 1462, Rarity.RARE, mage.cards.u.UnholyGrotto.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Unholy Grotto", "1462b", Rarity.RARE, mage.cards.u.UnholyGrotto.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ajani Goldmane", 1453, Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Ajani Goldmane", "1453b", Rarity.MYTHIC, mage.cards.a.AjaniGoldmane.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace Beleren", 1454, Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace Beleren", "1454b", Rarity.MYTHIC, mage.cards.j.JaceBeleren.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana Vess", 1455, Rarity.MYTHIC, mage.cards.l.LilianaVess.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana Vess", "1455b", Rarity.MYTHIC, mage.cards.l.LilianaVess.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chandra Nalaar", 1456, Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chandra Nalaar", "1456b", Rarity.MYTHIC, mage.cards.c.ChandraNalaar.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Garruk Wildspeaker", 1457, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Garruk Wildspeaker", "1457b", Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Death Baron", 1458, Rarity.RARE, mage.cards.d.DeathBaron.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Death Baron", "1458b", Rarity.RARE, mage.cards.d.DeathBaron.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Noxious Ghoul", 1459, Rarity.RARE, mage.cards.n.NoxiousGhoul.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Noxious Ghoul", "1459b", Rarity.RARE, mage.cards.n.NoxiousGhoul.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Zombie Master", 1460, Rarity.RARE, mage.cards.z.ZombieMaster.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Zombie Master", "1460b", Rarity.RARE, mage.cards.z.ZombieMaster.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Grimgrin, Corpse-Born", 1461, Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Grimgrin, Corpse-Born", "1461b", Rarity.MYTHIC, mage.cards.g.GrimgrinCorpseBorn.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Unholy Grotto", 1462, Rarity.RARE, mage.cards.u.UnholyGrotto.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Unholy Grotto", "1462b", Rarity.RARE, mage.cards.u.UnholyGrotto.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Giver of Runes", 1463, Rarity.RARE, mage.cards.g.GiverOfRunes.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Giver of Runes", "1463*", Rarity.RARE, mage.cards.g.GiverOfRunes.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Distant Melody", 1464, Rarity.RARE, mage.cards.d.DistantMelody.class, NON_FULL_USE_VARIOUS)); @@ -1459,17 +1448,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Thought Vessel", "1495*", Rarity.RARE, mage.cards.t.ThoughtVessel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Command Tower", 1496, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Command Tower", "1496*", Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Beacon of Tomorrows", 1497, Rarity.RARE, mage.cards.b.BeaconOfTomorrows.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Beacon of Tomorrows", "1497*", Rarity.RARE, mage.cards.b.BeaconOfTomorrows.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nexus of Fate", 1498, Rarity.MYTHIC, mage.cards.n.NexusOfFate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nexus of Fate", "1498*", Rarity.MYTHIC, mage.cards.n.NexusOfFate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Time Reversal", 1499, Rarity.MYTHIC, mage.cards.t.TimeReversal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Time Reversal", "1499*", Rarity.MYTHIC, mage.cards.t.TimeReversal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Time Stop", 1500, Rarity.RARE, mage.cards.t.TimeStop.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Time Stop", "1500*", Rarity.RARE, mage.cards.t.TimeStop.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Beacon of Tomorrows", 1497, Rarity.RARE, mage.cards.b.BeaconOfTomorrows.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Beacon of Tomorrows", "1497*", Rarity.RARE, mage.cards.b.BeaconOfTomorrows.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Nexus of Fate", 1498, Rarity.MYTHIC, mage.cards.n.NexusOfFate.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Nexus of Fate", "1498*", Rarity.MYTHIC, mage.cards.n.NexusOfFate.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Time Reversal", 1499, Rarity.MYTHIC, mage.cards.t.TimeReversal.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Time Reversal", "1499*", Rarity.MYTHIC, mage.cards.t.TimeReversal.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Time Stop", 1500, Rarity.RARE, mage.cards.t.TimeStop.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Time Stop", "1500*", Rarity.RARE, mage.cards.t.TimeStop.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Lara Croft, Tomb Raider", 1501, Rarity.MYTHIC, mage.cards.l.LaraCroftTombRaider.class)); cards.add(new SetCardInfo("Search for Azcanta", 1502, Rarity.RARE, mage.cards.s.SearchForAzcanta.class)); - cards.add(new SetCardInfo("Azcanta, the Sunken Ruin", 1502, Rarity.RARE, mage.cards.a.AzcantaTheSunkenRuin.class)); cards.add(new SetCardInfo("Anger of the Gods", 1503, Rarity.RARE, mage.cards.a.AngerOfTheGods.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bow of Nylea", 1504, Rarity.RARE, mage.cards.b.BowOfNylea.class)); cards.add(new SetCardInfo("Shadowspear", 1505, Rarity.RARE, mage.cards.s.Shadowspear.class)); @@ -1487,16 +1475,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Plains", 1513, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 1514, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 1515, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); - cards.add(new SetCardInfo("Wall of Omens", 1518, Rarity.RARE, mage.cards.w.WallOfOmens.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wall of Omens", "1518*", Rarity.RARE, mage.cards.w.WallOfOmens.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Circular Logic", 1519, Rarity.RARE, mage.cards.c.CircularLogic.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Circular Logic", "1519*", Rarity.RARE, mage.cards.c.CircularLogic.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Scheming Symmetry", 1520, Rarity.RARE, mage.cards.s.SchemingSymmetry.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Scheming Symmetry", "1520*", Rarity.RARE, mage.cards.s.SchemingSymmetry.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Price of Progress", 1521, Rarity.RARE, mage.cards.p.PriceOfProgress.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Price of Progress", "1521*", Rarity.RARE, mage.cards.p.PriceOfProgress.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Eternal Witness", 1522, Rarity.RARE, mage.cards.e.EternalWitness.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Eternal Witness", "1522*", Rarity.RARE, mage.cards.e.EternalWitness.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wall of Omens", 1518, Rarity.RARE, mage.cards.w.WallOfOmens.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Wall of Omens", "1518*", Rarity.RARE, mage.cards.w.WallOfOmens.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Circular Logic", 1519, Rarity.RARE, mage.cards.c.CircularLogic.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Circular Logic", "1519*", Rarity.RARE, mage.cards.c.CircularLogic.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Scheming Symmetry", 1520, Rarity.RARE, mage.cards.s.SchemingSymmetry.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Scheming Symmetry", "1520*", Rarity.RARE, mage.cards.s.SchemingSymmetry.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Price of Progress", 1521, Rarity.RARE, mage.cards.p.PriceOfProgress.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Price of Progress", "1521*", Rarity.RARE, mage.cards.p.PriceOfProgress.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Eternal Witness", 1522, Rarity.RARE, mage.cards.e.EternalWitness.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Eternal Witness", "1522*", Rarity.RARE, mage.cards.e.EternalWitness.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Inspiring Overseer", 1523, Rarity.RARE, mage.cards.i.InspiringOverseer.class)); cards.add(new SetCardInfo("Consider", 1524, Rarity.RARE, mage.cards.c.Consider.class)); cards.add(new SetCardInfo("Price of Glory", 1525, Rarity.RARE, mage.cards.p.PriceOfGlory.class)); @@ -1516,14 +1504,14 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Reflecting Pool", "1535*", Rarity.RARE, mage.cards.r.ReflectingPool.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reliquary Tower", 1536, Rarity.RARE, mage.cards.r.ReliquaryTower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reliquary Tower", "1536*", Rarity.RARE, mage.cards.r.ReliquaryTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sakashima of a Thousand Faces", 1541, Rarity.MYTHIC, mage.cards.s.SakashimaOfAThousandFaces.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sakashima of a Thousand Faces", "1541b", Rarity.MYTHIC, mage.cards.s.SakashimaOfAThousandFaces.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yargle, Glutton of Urborg", 1542, Rarity.RARE, mage.cards.y.YargleGluttonOfUrborg.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yargle, Glutton of Urborg", "1542b", Rarity.RARE, mage.cards.y.YargleGluttonOfUrborg.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krark, the Thumbless", 1543, Rarity.RARE, mage.cards.k.KrarkTheThumbless.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Krark, the Thumbless", "1543b", Rarity.RARE, mage.cards.k.KrarkTheThumbless.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Adrix and Nev, Twincasters", 1544, Rarity.MYTHIC, mage.cards.a.AdrixAndNevTwincasters.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Adrix and Nev, Twincasters", "1544b", Rarity.MYTHIC, mage.cards.a.AdrixAndNevTwincasters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sakashima of a Thousand Faces", 1541, Rarity.MYTHIC, mage.cards.s.SakashimaOfAThousandFaces.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Sakashima of a Thousand Faces", "1541b", Rarity.MYTHIC, mage.cards.s.SakashimaOfAThousandFaces.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Yargle, Glutton of Urborg", 1542, Rarity.RARE, mage.cards.y.YargleGluttonOfUrborg.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Yargle, Glutton of Urborg", "1542b", Rarity.RARE, mage.cards.y.YargleGluttonOfUrborg.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Krark, the Thumbless", 1543, Rarity.RARE, mage.cards.k.KrarkTheThumbless.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Krark, the Thumbless", "1543b", Rarity.RARE, mage.cards.k.KrarkTheThumbless.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Adrix and Nev, Twincasters", 1544, Rarity.MYTHIC, mage.cards.a.AdrixAndNevTwincasters.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Adrix and Nev, Twincasters", "1544b", Rarity.MYTHIC, mage.cards.a.AdrixAndNevTwincasters.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Denial", 1545, Rarity.RARE, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Denial", "1545*", Rarity.RARE, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nightscape Familiar", 1546, Rarity.RARE, mage.cards.n.NightscapeFamiliar.class, NON_FULL_USE_VARIOUS)); @@ -1561,21 +1549,21 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Anowon, the Ruin Thief", "1568*", Rarity.MYTHIC, mage.cards.a.AnowonTheRuinThief.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grenzo, Dungeon Warden", 1569, Rarity.RARE, mage.cards.g.GrenzoDungeonWarden.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grenzo, Dungeon Warden", "1569*", Rarity.RARE, mage.cards.g.GrenzoDungeonWarden.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Blade of Selves", 1570, Rarity.RARE, mage.cards.b.BladeOfSelves.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Conqueror's Flail", 1571, Rarity.RARE, mage.cards.c.ConquerorsFlail.class)); - cards.add(new SetCardInfo("Darksteel Plate", 1572, Rarity.RARE, mage.cards.d.DarksteelPlate.class)); - cards.add(new SetCardInfo("Deathrender", 1573, Rarity.RARE, mage.cards.d.Deathrender.class)); - cards.add(new SetCardInfo("Whispersilk Cloak", 1574, Rarity.RARE, mage.cards.w.WhispersilkCloak.class)); - cards.add(new SetCardInfo("Reconnaissance", 1575, Rarity.RARE, mage.cards.r.Reconnaissance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reconnaissance", "1575*", Rarity.RARE, mage.cards.r.Reconnaissance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace, Wielder of Mysteries", 1576, Rarity.RARE, mage.cards.j.JaceWielderOfMysteries.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jace, Wielder of Mysteries", "1576*", Rarity.RARE, mage.cards.j.JaceWielderOfMysteries.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Black Market", 1577, Rarity.RARE, mage.cards.b.BlackMarket.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Black Market", "1577*", Rarity.RARE, mage.cards.b.BlackMarket.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire Undercurrents", 1578, Rarity.RARE, mage.cards.d.DireUndercurrents.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire Undercurrents", "1578*", Rarity.RARE, mage.cards.d.DireUndercurrents.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Obeka, Brute Chronologist", 1579, Rarity.MYTHIC, mage.cards.o.ObekaBruteChronologist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Obeka, Brute Chronologist", "1579*", Rarity.MYTHIC, mage.cards.o.ObekaBruteChronologist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade of Selves", 1570, Rarity.RARE, mage.cards.b.BladeOfSelves.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Conqueror's Flail", 1571, Rarity.RARE, mage.cards.c.ConquerorsFlail.class, FULL_ART)); + cards.add(new SetCardInfo("Darksteel Plate", 1572, Rarity.RARE, mage.cards.d.DarksteelPlate.class, FULL_ART)); + cards.add(new SetCardInfo("Deathrender", 1573, Rarity.RARE, mage.cards.d.Deathrender.class, FULL_ART)); + cards.add(new SetCardInfo("Whispersilk Cloak", 1574, Rarity.RARE, mage.cards.w.WhispersilkCloak.class, FULL_ART)); + cards.add(new SetCardInfo("Reconnaissance", 1575, Rarity.RARE, mage.cards.r.Reconnaissance.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Reconnaissance", "1575*", Rarity.RARE, mage.cards.r.Reconnaissance.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace, Wielder of Mysteries", 1576, Rarity.RARE, mage.cards.j.JaceWielderOfMysteries.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace, Wielder of Mysteries", "1576*", Rarity.RARE, mage.cards.j.JaceWielderOfMysteries.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Black Market", 1577, Rarity.RARE, mage.cards.b.BlackMarket.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Black Market", "1577*", Rarity.RARE, mage.cards.b.BlackMarket.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Dire Undercurrents", 1578, Rarity.RARE, mage.cards.d.DireUndercurrents.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Dire Undercurrents", "1578*", Rarity.RARE, mage.cards.d.DireUndercurrents.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Obeka, Brute Chronologist", 1579, Rarity.MYTHIC, mage.cards.o.ObekaBruteChronologist.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Obeka, Brute Chronologist", "1579*", Rarity.MYTHIC, mage.cards.o.ObekaBruteChronologist.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Rose Noble", 1580, Rarity.RARE, mage.cards.r.RoseNoble.class)); cards.add(new SetCardInfo("The Meep", 1581, Rarity.RARE, mage.cards.t.TheMeep.class)); // cards.add(new SetCardInfo("The Celestial Toymaker", 1582, Rarity.RARE, mage.cards.t.TheCelestialToymaker.class)); @@ -1609,14 +1597,12 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Inspiring Vantage", 1605, Rarity.RARE, mage.cards.i.InspiringVantage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Inspiring Vantage", "1605*", Rarity.RARE, mage.cards.i.InspiringVantage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scrying Sheets", 1606, Rarity.RARE, mage.cards.s.ScryingSheets.class)); - cards.add(new SetCardInfo("Thespian's Stage", 1607, Rarity.RARE, mage.cards.t.ThespiansStage.class)); + cards.add(new SetCardInfo("Thespian's Stage", 1607, Rarity.RARE, mage.cards.t.ThespiansStage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avabruck Caretaker", 1608, Rarity.MYTHIC, mage.cards.a.AvabruckCaretaker.class)); - cards.add(new SetCardInfo("Hollowhenge Huntmaster", 1608, Rarity.MYTHIC, mage.cards.h.HollowhengeHuntmaster.class)); cards.add(new SetCardInfo("Beastmaster Ascension", 1609, Rarity.RARE, mage.cards.b.BeastmasterAscension.class)); cards.add(new SetCardInfo("Howl of the Night Pack", 1610, Rarity.RARE, mage.cards.h.HowlOfTheNightPack.class)); cards.add(new SetCardInfo("Second Harvest", 1611, Rarity.RARE, mage.cards.s.SecondHarvest.class)); cards.add(new SetCardInfo("Tovolar, Dire Overlord", 1612, Rarity.RARE, mage.cards.t.TovolarDireOverlord.class)); - cards.add(new SetCardInfo("Tovolar, the Midnight Scourge", 1612, Rarity.RARE, mage.cards.t.TovolarTheMidnightScourge.class)); cards.add(new SetCardInfo("Brash Taunter", 1614, Rarity.RARE, mage.cards.b.BrashTaunter.class)); cards.add(new SetCardInfo("Goblin Chieftain", 1615, Rarity.RARE, mage.cards.g.GoblinChieftain.class)); cards.add(new SetCardInfo("Goblin Ringleader", 1616, Rarity.RARE, mage.cards.g.GoblinRingleader.class)); @@ -1654,14 +1640,14 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Anger", "1637*", Rarity.RARE, mage.cards.a.Anger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Bolt", 1638, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Bolt", "1638*", Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inalla, Archmage Ritualist", 1639, Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Inalla, Archmage Ritualist", "1639*", Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aether Vial", 1640, Rarity.RARE, mage.cards.a.AetherVial.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aether Vial", "1640*", Rarity.RARE, mage.cards.a.AetherVial.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arcane Signet", 1641, Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arcane Signet", "1641*", Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sword of the Animist", 1642, Rarity.RARE, mage.cards.s.SwordOfTheAnimist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sword of the Animist", "1642*", Rarity.RARE, mage.cards.s.SwordOfTheAnimist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inalla, Archmage Ritualist", 1639, Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Inalla, Archmage Ritualist", "1639*", Rarity.MYTHIC, mage.cards.i.InallaArchmageRitualist.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Aether Vial", 1640, Rarity.RARE, mage.cards.a.AetherVial.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Aether Vial", "1640*", Rarity.RARE, mage.cards.a.AetherVial.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Signet", 1641, Rarity.RARE, mage.cards.a.ArcaneSignet.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Signet", "1641*", Rarity.RARE, mage.cards.a.ArcaneSignet.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Sword of the Animist", 1642, Rarity.RARE, mage.cards.s.SwordOfTheAnimist.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Sword of the Animist", "1642*", Rarity.RARE, mage.cards.s.SwordOfTheAnimist.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Gravebreaker Lamia", 1643, Rarity.RARE, mage.cards.g.GravebreakerLamia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gravebreaker Lamia", "1643*", Rarity.RARE, mage.cards.g.GravebreakerLamia.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aura Shards", 1644, Rarity.RARE, mage.cards.a.AuraShards.class, NON_FULL_USE_VARIOUS)); @@ -1670,16 +1656,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Fiend Artisan", "1645*", Rarity.MYTHIC, mage.cards.f.FiendArtisan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Karador, Ghost Chieftain", 1646, Rarity.MYTHIC, mage.cards.k.KaradorGhostChieftain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Karador, Ghost Chieftain", "1646*", Rarity.MYTHIC, mage.cards.k.KaradorGhostChieftain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 1647, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 1648, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 1649, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 1650, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 1651, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 1652, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 1653, Rarity.LAND, mage.cards.basiclands.Island.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 1654, Rarity.LAND, mage.cards.basiclands.Swamp.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 1655, Rarity.LAND, mage.cards.basiclands.Mountain.class, RETRO_ART_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 1656, Rarity.LAND, mage.cards.basiclands.Forest.class, RETRO_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 1647, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 1648, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 1649, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 1650, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 1651, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 1652, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 1653, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 1654, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 1655, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 1656, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Consecrated Sphinx", 1657, Rarity.MYTHIC, mage.cards.c.ConsecratedSphinx.class, RETRO_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Chaotic Goo", 1658, Rarity.RARE, mage.cards.c.ChaoticGoo.class, RETRO_ART)); cards.add(new SetCardInfo("Kiki-Jiki, Mirror Breaker", 1659, Rarity.MYTHIC, mage.cards.k.KikiJikiMirrorBreaker.class, RETRO_ART)); @@ -1725,21 +1711,21 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Kiora, Behemoth Beckoner", 1700, Rarity.RARE, mage.cards.k.KioraBehemothBeckoner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tezzeret, Master of the Bridge", 1701, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfTheBridge.class)); cards.add(new SetCardInfo("Vraska, Golgari Queen", 1702, Rarity.MYTHIC, mage.cards.v.VraskaGolgariQueen.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jaxis, the Troublemaker", 1703, Rarity.RARE, mage.cards.j.JaxisTheTroublemaker.class)); - cards.add(new SetCardInfo("Coffin Queen", 1704, Rarity.RARE, mage.cards.c.CoffinQueen.class)); - cards.add(new SetCardInfo("Goblin King", 1705, Rarity.RARE, mage.cards.g.GoblinKing.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Professional Face-Breaker", 1706, Rarity.RARE, mage.cards.p.ProfessionalFaceBreaker.class)); - cards.add(new SetCardInfo("Rankle, Master of Pranks", 1707, Rarity.MYTHIC, mage.cards.r.RankleMasterOfPranks.class)); + cards.add(new SetCardInfo("Jaxis, the Troublemaker", 1703, Rarity.RARE, mage.cards.j.JaxisTheTroublemaker.class, FULL_ART)); + cards.add(new SetCardInfo("Coffin Queen", 1704, Rarity.RARE, mage.cards.c.CoffinQueen.class, FULL_ART)); + cards.add(new SetCardInfo("Goblin King", 1705, Rarity.RARE, mage.cards.g.GoblinKing.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Professional Face-Breaker", 1706, Rarity.RARE, mage.cards.p.ProfessionalFaceBreaker.class, FULL_ART)); + cards.add(new SetCardInfo("Rankle, Master of Pranks", 1707, Rarity.MYTHIC, mage.cards.r.RankleMasterOfPranks.class, FULL_ART)); cards.add(new SetCardInfo("Soul Warden", 1708, Rarity.RARE, mage.cards.s.SoulWarden.class)); cards.add(new SetCardInfo("Shivan Dragon", 1709, Rarity.RARE, mage.cards.s.ShivanDragon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Elves of Deep Shadow", 1710, Rarity.RARE, mage.cards.e.ElvesOfDeepShadow.class)); cards.add(new SetCardInfo("Good-Fortune Unicorn", 1711, Rarity.RARE, mage.cards.g.GoodFortuneUnicorn.class)); cards.add(new SetCardInfo("Coat of Arms", 1712, Rarity.RARE, mage.cards.c.CoatOfArms.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dictate of Erebos", 1713, Rarity.RARE, mage.cards.d.DictateOfErebos.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fecundity", 1714, Rarity.RARE, mage.cards.f.Fecundity.class)); - cards.add(new SetCardInfo("Mayhem Devil", 1715, Rarity.RARE, mage.cards.m.MayhemDevil.class)); - cards.add(new SetCardInfo("Moldervine Reclamation", 1716, Rarity.RARE, mage.cards.m.MoldervineReclamation.class)); - cards.add(new SetCardInfo("Prossh, Skyraider of Kher", 1717, Rarity.MYTHIC, mage.cards.p.ProsshSkyraiderOfKher.class)); + cards.add(new SetCardInfo("Dictate of Erebos", 1713, Rarity.RARE, mage.cards.d.DictateOfErebos.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Fecundity", 1714, Rarity.RARE, mage.cards.f.Fecundity.class, FULL_ART)); + cards.add(new SetCardInfo("Mayhem Devil", 1715, Rarity.RARE, mage.cards.m.MayhemDevil.class, FULL_ART)); + cards.add(new SetCardInfo("Moldervine Reclamation", 1716, Rarity.RARE, mage.cards.m.MoldervineReclamation.class, FULL_ART)); + cards.add(new SetCardInfo("Prossh, Skyraider of Kher", 1717, Rarity.MYTHIC, mage.cards.p.ProsshSkyraiderOfKher.class, FULL_ART)); cards.add(new SetCardInfo("Back to Basics", 1718, Rarity.RARE, mage.cards.b.BackToBasics.class)); cards.add(new SetCardInfo("Preordain", 1719, Rarity.RARE, mage.cards.p.Preordain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sphinx of the Second Sun", 1720, Rarity.MYTHIC, mage.cards.s.SphinxOfTheSecondSun.class)); @@ -1782,11 +1768,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Dauthi Voidwalker", 1760, Rarity.RARE, mage.cards.d.DauthiVoidwalker.class)); cards.add(new SetCardInfo("Magus of the Moon", 1761, Rarity.RARE, mage.cards.m.MagusOfTheMoon.class)); cards.add(new SetCardInfo("Witch's Oven", 1762, Rarity.RARE, mage.cards.w.WitchsOven.class)); - cards.add(new SetCardInfo("Doom Whisperer", 1763, Rarity.MYTHIC, mage.cards.d.DoomWhisperer.class)); - cards.add(new SetCardInfo("Ravenous Chupacabra", 1764, Rarity.RARE, mage.cards.r.RavenousChupacabra.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Koma, Cosmos Serpent", 1765, Rarity.MYTHIC, mage.cards.k.KomaCosmosSerpent.class)); - cards.add(new SetCardInfo("Mazirek, Kraul Death Priest", 1766, Rarity.MYTHIC, mage.cards.m.MazirekKraulDeathPriest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Uril, the Miststalker", 1767, Rarity.MYTHIC, mage.cards.u.UrilTheMiststalker.class)); + cards.add(new SetCardInfo("Doom Whisperer", 1763, Rarity.MYTHIC, mage.cards.d.DoomWhisperer.class, FULL_ART)); + cards.add(new SetCardInfo("Ravenous Chupacabra", 1764, Rarity.RARE, mage.cards.r.RavenousChupacabra.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Koma, Cosmos Serpent", 1765, Rarity.MYTHIC, mage.cards.k.KomaCosmosSerpent.class, FULL_ART)); + cards.add(new SetCardInfo("Mazirek, Kraul Death Priest", 1766, Rarity.MYTHIC, mage.cards.m.MazirekKraulDeathPriest.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Uril, the Miststalker", 1767, Rarity.MYTHIC, mage.cards.u.UrilTheMiststalker.class, FULL_ART)); cards.add(new SetCardInfo("Careful Study", 1768, Rarity.RARE, mage.cards.c.CarefulStudy.class)); cards.add(new SetCardInfo("Living End", 1769, Rarity.MYTHIC, mage.cards.l.LivingEnd.class)); cards.add(new SetCardInfo("Eladamri's Call", 1770, Rarity.RARE, mage.cards.e.EladamrisCall.class)); @@ -1832,11 +1818,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Varragoth, Bloodsky Sire", 1809, Rarity.RARE, mage.cards.v.VarragothBloodskySire.class)); cards.add(new SetCardInfo("Twinflame", 1810, Rarity.RARE, mage.cards.t.Twinflame.class)); cards.add(new SetCardInfo("Genesis Chamber", 1811, Rarity.RARE, mage.cards.g.GenesisChamber.class)); - cards.add(new SetCardInfo("Silence", 1816, Rarity.RARE, mage.cards.s.Silence.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Winds of Abandon", 1817, Rarity.RARE, mage.cards.w.WindsOfAbandon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Culling the Weak", 1818, Rarity.RARE, mage.cards.c.CullingTheWeak.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fatal Push", 1819, Rarity.RARE, mage.cards.f.FatalPush.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Young Wolf", 1820, Rarity.RARE, mage.cards.y.YoungWolf.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silence", 1816, Rarity.RARE, mage.cards.s.Silence.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Winds of Abandon", 1817, Rarity.RARE, mage.cards.w.WindsOfAbandon.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Culling the Weak", 1818, Rarity.RARE, mage.cards.c.CullingTheWeak.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Fatal Push", 1819, Rarity.RARE, mage.cards.f.FatalPush.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Young Wolf", 1820, Rarity.RARE, mage.cards.y.YoungWolf.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Mana Geyser", 1821, Rarity.RARE, mage.cards.m.ManaGeyser.class)); cards.add(new SetCardInfo("Lightning Bolt", 1822, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fierce Guardianship", 1823, Rarity.RARE, mage.cards.f.FierceGuardianship.class)); @@ -1887,14 +1873,14 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Damn", 1870, Rarity.RARE, mage.cards.d.Damn.class)); cards.add(new SetCardInfo("Lightning Bolt", 1871, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heroic Intervention", 1872, Rarity.RARE, mage.cards.h.HeroicIntervention.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aesi, Tyrant of Gyre Strait", 1873, Rarity.MYTHIC, mage.cards.a.AesiTyrantOfGyreStrait.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aesi, Tyrant of Gyre Strait", "1873b", Rarity.MYTHIC, mage.cards.a.AesiTyrantOfGyreStrait.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Anje Falkenrath", 1874, Rarity.MYTHIC, mage.cards.a.AnjeFalkenrath.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Anje Falkenrath", "1874b", Rarity.MYTHIC, mage.cards.a.AnjeFalkenrath.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chulane, Teller of Tales", 1875, Rarity.MYTHIC, mage.cards.c.ChulaneTellerOfTales.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chulane, Teller of Tales", "1875b", Rarity.MYTHIC, mage.cards.c.ChulaneTellerOfTales.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Radha, Heart of Keld", 1876, Rarity.RARE, mage.cards.r.RadhaHeartOfKeld.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Radha, Heart of Keld", "1876b", Rarity.RARE, mage.cards.r.RadhaHeartOfKeld.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aesi, Tyrant of Gyre Strait", 1873, Rarity.MYTHIC, mage.cards.a.AesiTyrantOfGyreStrait.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Aesi, Tyrant of Gyre Strait", "1873b", Rarity.MYTHIC, mage.cards.a.AesiTyrantOfGyreStrait.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Anje Falkenrath", 1874, Rarity.MYTHIC, mage.cards.a.AnjeFalkenrath.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Anje Falkenrath", "1874b", Rarity.MYTHIC, mage.cards.a.AnjeFalkenrath.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chulane, Teller of Tales", 1875, Rarity.MYTHIC, mage.cards.c.ChulaneTellerOfTales.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Chulane, Teller of Tales", "1875b", Rarity.MYTHIC, mage.cards.c.ChulaneTellerOfTales.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Radha, Heart of Keld", 1876, Rarity.RARE, mage.cards.r.RadhaHeartOfKeld.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Radha, Heart of Keld", "1876b", Rarity.RARE, mage.cards.r.RadhaHeartOfKeld.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 1877, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class)); cards.add(new SetCardInfo("Murktide Regent", 1878, Rarity.MYTHIC, mage.cards.m.MurktideRegent.class)); cards.add(new SetCardInfo("Lightning Bolt", 1879, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); @@ -1975,16 +1961,16 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Liesa, Shroud of Dusk", 1961, Rarity.RARE, mage.cards.l.LiesaShroudOfDusk.class)); cards.add(new SetCardInfo("Oloro, Ageless Ascetic", 1962, Rarity.MYTHIC, mage.cards.o.OloroAgelessAscetic.class)); cards.add(new SetCardInfo("Sythis, Harvest's Hand", 1963, Rarity.RARE, mage.cards.s.SythisHarvestsHand.class)); - cards.add(new SetCardInfo("Parhelion II", 1964, Rarity.RARE, mage.cards.p.ParhelionII.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Parhelion II", "1964b", Rarity.RARE, mage.cards.p.ParhelionII.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mechtitan Core", 1965, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mechtitan Core", "1965b", Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Peacewalker Colossus", 1966, Rarity.RARE, mage.cards.p.PeacewalkerColossus.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Peacewalker Colossus", "1966b", Rarity.RARE, mage.cards.p.PeacewalkerColossus.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reckoner Bankbuster", 1967, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reckoner Bankbuster", "1967b", Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Smuggler's Copter", 1968, Rarity.RARE, mage.cards.s.SmugglersCopter.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Smuggler's Copter", "1968b", Rarity.RARE, mage.cards.s.SmugglersCopter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Parhelion II", 1964, Rarity.RARE, mage.cards.p.ParhelionII.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Parhelion II", "1964b", Rarity.RARE, mage.cards.p.ParhelionII.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Mechtitan Core", 1965, Rarity.RARE, mage.cards.m.MechtitanCore.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Mechtitan Core", "1965b", Rarity.RARE, mage.cards.m.MechtitanCore.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Peacewalker Colossus", 1966, Rarity.RARE, mage.cards.p.PeacewalkerColossus.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Peacewalker Colossus", "1966b", Rarity.RARE, mage.cards.p.PeacewalkerColossus.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckoner Bankbuster", 1967, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckoner Bankbuster", "1967b", Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Smuggler's Copter", 1968, Rarity.RARE, mage.cards.s.SmugglersCopter.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Smuggler's Copter", "1968b", Rarity.RARE, mage.cards.s.SmugglersCopter.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord Atarka", 1970, Rarity.MYTHIC, mage.cards.d.DragonlordAtarka.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord Atarka", "1970b", Rarity.MYTHIC, mage.cards.d.DragonlordAtarka.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord Dromoka", 1971, Rarity.MYTHIC, mage.cards.d.DragonlordDromoka.class, NON_FULL_USE_VARIOUS)); @@ -2025,11 +2011,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Treasonous Ogre", 2007, Rarity.RARE, mage.cards.t.TreasonousOgre.class)); cards.add(new SetCardInfo("Uncivil Unrest", 2008, Rarity.RARE, mage.cards.u.UncivilUnrest.class)); cards.add(new SetCardInfo("Marchesa, the Black Rose", 2009, Rarity.RARE, mage.cards.m.MarchesaTheBlackRose.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashaya, Soul of the Wild", 2014, Rarity.MYTHIC, mage.cards.a.AshayaSoulOfTheWild.class)); - cards.add(new SetCardInfo("Elvish Reclaimer", 2015, Rarity.RARE, mage.cards.e.ElvishReclaimer.class)); - cards.add(new SetCardInfo("Harrow", 2016, Rarity.RARE, mage.cards.h.Harrow.class)); - cards.add(new SetCardInfo("World Shaper", 2017, Rarity.RARE, mage.cards.w.WorldShaper.class)); - cards.add(new SetCardInfo("Horn of Greed", 2018, Rarity.RARE, mage.cards.h.HornOfGreed.class)); + cards.add(new SetCardInfo("Ashaya, Soul of the Wild", 2014, Rarity.MYTHIC, mage.cards.a.AshayaSoulOfTheWild.class, FULL_ART)); + cards.add(new SetCardInfo("Elvish Reclaimer", 2015, Rarity.RARE, mage.cards.e.ElvishReclaimer.class, FULL_ART)); + cards.add(new SetCardInfo("Harrow", 2016, Rarity.RARE, mage.cards.h.Harrow.class, FULL_ART)); + cards.add(new SetCardInfo("World Shaper", 2017, Rarity.RARE, mage.cards.w.WorldShaper.class, FULL_ART)); + cards.add(new SetCardInfo("Horn of Greed", 2018, Rarity.RARE, mage.cards.h.HornOfGreed.class, FULL_ART)); cards.add(new SetCardInfo("Damnation", 2019, Rarity.RARE, mage.cards.d.Damnation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark Ritual", 2020, Rarity.RARE, mage.cards.d.DarkRitual.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Peer into the Abyss", 2021, Rarity.RARE, mage.cards.p.PeerIntoTheAbyss.class, NON_FULL_USE_VARIOUS)); @@ -2066,14 +2052,14 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Tireless Provisioner", 2057, Rarity.RARE, mage.cards.t.TirelessProvisioner.class)); cards.add(new SetCardInfo("Sylvan Library", 2058, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); cards.add(new SetCardInfo("Ancient Greenwarden", 2059, Rarity.MYTHIC, mage.cards.a.AncientGreenwarden.class)); - cards.add(new SetCardInfo("Expressive Iteration", 2060, Rarity.RARE, mage.cards.e.ExpressiveIteration.class)); + cards.add(new SetCardInfo("Expressive Iteration", 2060, Rarity.RARE, mage.cards.e.ExpressiveIteration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Xenagos, God of Revels", 2061, Rarity.MYTHIC, mage.cards.x.XenagosGodOfRevels.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lightning Greaves", 2062, Rarity.RARE, mage.cards.l.LightningGreaves.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sol Ring", 2063, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cultural Exchange", 2071, Rarity.RARE, mage.cards.c.CulturalExchange.class)); - cards.add(new SetCardInfo("Folio of Fancies", 2072, Rarity.RARE, mage.cards.f.FolioOfFancies.class)); - cards.add(new SetCardInfo("Concordant Crossroads", 2073, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Rites of Flourishing", 2074, Rarity.RARE, mage.cards.r.RitesOfFlourishing.class)); + cards.add(new SetCardInfo("Folio of Fancies", 2072, Rarity.RARE, mage.cards.f.FolioOfFancies.class, FULL_ART)); + cards.add(new SetCardInfo("Concordant Crossroads", 2073, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class, FULL_ART_USE_VARIOUS)); + cards.add(new SetCardInfo("Rites of Flourishing", 2074, Rarity.RARE, mage.cards.r.RitesOfFlourishing.class, FULL_ART)); cards.add(new SetCardInfo("Font of Mythos", 2075, Rarity.RARE, mage.cards.f.FontOfMythos.class)); cards.add(new SetCardInfo("Plains", 2076, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", 2077, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); @@ -2139,23 +2125,22 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Swords to Plowshares", 2167, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baral, Chief of Compliance", 2168, Rarity.RARE, mage.cards.b.BaralChiefOfCompliance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Garruk Relentless", 2169, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); - cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 2169, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); cards.add(new SetCardInfo("Reaper King", 2170, Rarity.RARE, mage.cards.r.ReaperKing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Glen Elendra Archmage", 2171, Rarity.RARE, mage.cards.g.GlenElendraArchmage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Guardian Project", 2172, Rarity.MYTHIC, mage.cards.g.GuardianProject.class)); cards.add(new SetCardInfo("Roon of the Hidden Realm", 2173, Rarity.RARE, mage.cards.r.RoonOfTheHiddenRealm.class)); cards.add(new SetCardInfo("Soulherder", 2174, Rarity.RARE, mage.cards.s.Soulherder.class)); - cards.add(new SetCardInfo("Jaws, Relentless Predator", 2175, Rarity.MYTHIC, mage.cards.j.JawsRelentlessPredator.class)); + cards.add(new SetCardInfo("Jaws, Relentless Predator", 2175, Rarity.MYTHIC, mage.cards.j.JawsRelentlessPredator.class, FULL_ART)); cards.add(new SetCardInfo("Descent into Avernus", 2176, Rarity.RARE, mage.cards.d.DescentIntoAvernus.class)); cards.add(new SetCardInfo("Reckless Endeavor", 2177, Rarity.RARE, mage.cards.r.RecklessEndeavor.class)); cards.add(new SetCardInfo("Sneak Attack", 2178, Rarity.MYTHIC, mage.cards.s.SneakAttack.class)); cards.add(new SetCardInfo("Abrade", 2179, Rarity.RARE, mage.cards.a.Abrade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bruvac the Grandiloquent", 2181, Rarity.MYTHIC, mage.cards.b.BruvacTheGrandiloquent.class)); - cards.add(new SetCardInfo("Windfall", 2182, Rarity.RARE, mage.cards.w.Windfall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Windfall", 2182, Rarity.RARE, mage.cards.w.Windfall.class, FULL_ART_USE_VARIOUS)); cards.add(new SetCardInfo("Captain N'ghathrod", 2183, Rarity.MYTHIC, mage.cards.c.CaptainNghathrod.class)); cards.add(new SetCardInfo("Nekusar, the Mindrazer", 2184, Rarity.RARE, mage.cards.n.NekusarTheMindrazer.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Iron Maiden", 2185, Rarity.RARE, mage.cards.i.IronMaiden.class)); - cards.add(new SetCardInfo("Mindcrank", 2186, Rarity.RARE, mage.cards.m.Mindcrank.class)); + cards.add(new SetCardInfo("Iron Maiden", 2185, Rarity.RARE, mage.cards.i.IronMaiden.class, FULL_ART)); + cards.add(new SetCardInfo("Mindcrank", 2186, Rarity.RARE, mage.cards.m.Mindcrank.class, FULL_ART)); cards.add(new SetCardInfo("Lethal Scheme", 2187, Rarity.RARE, mage.cards.l.LethalScheme.class)); cards.add(new SetCardInfo("Grave Titan", 2188, Rarity.MYTHIC, mage.cards.g.GraveTitan.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Animate Dead", 2189, Rarity.RARE, mage.cards.a.AnimateDead.class)); @@ -2180,9 +2165,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Sulfuric Vortex", 2210, Rarity.RARE, mage.cards.s.SulfuricVortex.class)); cards.add(new SetCardInfo("Pyrohemia", 2211, Rarity.RARE, mage.cards.p.Pyrohemia.class)); cards.add(new SetCardInfo("Atreus, Impulsive Son", 2212, Rarity.MYTHIC, mage.cards.a.AtreusImpulsiveSon.class)); + cards.add(new SetCardInfo("Kratos, Stoic Father", 2213, Rarity.MYTHIC, mage.cards.k.KratosStoicFather.class)); cards.add(new SetCardInfo("Teferi's Ageless Insight", 2214, Rarity.RARE, mage.cards.t.TeferisAgelessInsight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi's Ageless Insight", "2214b", Rarity.RARE, mage.cards.t.TeferisAgelessInsight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Iroas, God of Victory", 2215, Rarity.MYTHIC, mage.cards.i.IroasGodOfVictory.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nathan Drake, Treasure Hunter", 2216, Rarity.MYTHIC, mage.cards.n.NathanDrakeTreasureHunter.class)); cards.add(new SetCardInfo("Midnight Clock", 2217, Rarity.RARE, mage.cards.m.MidnightClock.class)); cards.add(new SetCardInfo("Whip of Erebos", 2218, Rarity.RARE, mage.cards.w.WhipOfErebos.class)); cards.add(new SetCardInfo("Chain Reaction", 2219, Rarity.RARE, mage.cards.c.ChainReaction.class)); @@ -2192,6 +2179,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Blightsteel Colossus", 2223, Rarity.MYTHIC, mage.cards.b.BlightsteelColossus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tarrian's Soulcleaver", 2224, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class)); cards.add(new SetCardInfo("Meteor Golem", 2225, Rarity.RARE, mage.cards.m.MeteorGolem.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin Sakai, Ghost of Tsushima", 2226, Rarity.MYTHIC, mage.cards.j.JinSakaiGhostOfTsushima.class)); cards.add(new SetCardInfo("Path to Exile", 2227, Rarity.RARE, mage.cards.p.PathToExile.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Borne Upon a Wind", 2228, Rarity.RARE, mage.cards.b.BorneUponAWind.class)); cards.add(new SetCardInfo("Ghostly Flicker", 2229, Rarity.RARE, mage.cards.g.GhostlyFlicker.class)); @@ -2201,6 +2189,30 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Voja, Jaws of the Conclave", 2284, Rarity.MYTHIC, mage.cards.v.VojaJawsOfTheConclave.class)); cards.add(new SetCardInfo("Wilhelt, the Rotcleaver", 2285, Rarity.MYTHIC, mage.cards.w.WilheltTheRotcleaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Liberator, Urza's Battlethopter", 2286, Rarity.RARE, mage.cards.l.LiberatorUrzasBattlethopter.class)); + cards.add(new SetCardInfo("Torment of Hailfire", 2287, Rarity.RARE, mage.cards.t.TormentOfHailfire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blood Moon", 2288, Rarity.RARE, mage.cards.b.BloodMoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lightning Bolt", 2289, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dramatic Entrance", 2290, Rarity.RARE, mage.cards.d.DramaticEntrance.class)); + cards.add(new SetCardInfo("Serra Ascendant", 2291, Rarity.RARE, mage.cards.s.SerraAscendant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ponder", 2292, Rarity.RARE, mage.cards.p.Ponder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cryptolith Rite", 2293, Rarity.RARE, mage.cards.c.CryptolithRite.class)); + cards.add(new SetCardInfo("Kodama's Reach", 2294, Rarity.RARE, mage.cards.k.KodamasReach.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chain of Vapor", 2295, Rarity.RARE, mage.cards.c.ChainOfVapor.class)); + cards.add(new SetCardInfo("Meltdown", 2296, Rarity.RARE, mage.cards.m.Meltdown.class)); + cards.add(new SetCardInfo("Nature's Claim", 2297, Rarity.RARE, mage.cards.n.NaturesClaim.class)); + cards.add(new SetCardInfo("Anguished Unmaking", 2298, Rarity.RARE, mage.cards.a.AnguishedUnmaking.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Putrefy", 2299, Rarity.RARE, mage.cards.p.Putrefy.class)); + cards.add(new SetCardInfo("Silence", 2300, Rarity.RARE, mage.cards.s.Silence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Preordain", 2301, Rarity.COMMON, mage.cards.p.Preordain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Painful Truths", 2302, Rarity.RARE, mage.cards.p.PainfulTruths.class)); + cards.add(new SetCardInfo("Past in Flames", 2303, Rarity.MYTHIC, mage.cards.p.PastInFlames.class)); + cards.add(new SetCardInfo("Force of Vigor", 2304, Rarity.RARE, mage.cards.f.ForceOfVigor.class)); + cards.add(new SetCardInfo("Expressive Iteration", 2305, Rarity.RARE, mage.cards.e.ExpressiveIteration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phantasmal Image", 2306, Rarity.RARE, mage.cards.p.PhantasmalImage.class)); + cards.add(new SetCardInfo("Braid of Fire", 2307, Rarity.RARE, mage.cards.b.BraidOfFire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cursed Mirror", 2308, Rarity.RARE, mage.cards.c.CursedMirror.class)); + cards.add(new SetCardInfo("Mask of Memory", 2309, Rarity.RARE, mage.cards.m.MaskOfMemory.class)); + cards.add(new SetCardInfo("Thespian's Stage", 2310, Rarity.RARE, mage.cards.t.ThespiansStage.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Distant Melody", 2311, Rarity.RARE, mage.cards.d.DistantMelody.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Explore", 2312, Rarity.RARE, mage.cards.e.Explore.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Inspiring Call", 2313, Rarity.RARE, mage.cards.i.InspiringCall.class)); @@ -2248,7 +2260,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Jace, the Mind Sculptor", 8001, Rarity.MYTHIC, mage.cards.j.JaceTheMindSculptor.class)); cards.add(new SetCardInfo("Doom Blade", 9990, Rarity.RARE, mage.cards.d.DoomBlade.class)); cards.add(new SetCardInfo("Massacre", 9991, Rarity.RARE, mage.cards.m.Massacre.class)); - cards.add(new SetCardInfo("Torment of Hailfire", 9992, Rarity.RARE, mage.cards.t.TormentOfHailfire.class)); + cards.add(new SetCardInfo("Torment of Hailfire", 9992, Rarity.RARE, mage.cards.t.TormentOfHailfire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ruination", 9993, Rarity.RARE, mage.cards.r.Ruination.class)); cards.add(new SetCardInfo("Mogis, God of Slaughter", 9994, Rarity.MYTHIC, mage.cards.m.MogisGodOfSlaughter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Garruk, Caller of Beasts", 9995, Rarity.MYTHIC, mage.cards.g.GarrukCallerOfBeasts.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairShowdown.java b/Mage.Sets/src/mage/sets/SecretLairPromo.java similarity index 92% rename from Mage.Sets/src/mage/sets/SecretLairShowdown.java rename to Mage.Sets/src/mage/sets/SecretLairPromo.java index 3f32c7ceb5b..5c17194773c 100644 --- a/Mage.Sets/src/mage/sets/SecretLairShowdown.java +++ b/Mage.Sets/src/mage/sets/SecretLairPromo.java @@ -7,16 +7,16 @@ import mage.constants.SetType; /** * https://scryfall.com/sets/slp */ -public class SecretLairShowdown extends ExpansionSet { +public class SecretLairPromo extends ExpansionSet { - private static final SecretLairShowdown instance = new SecretLairShowdown(); + private static final SecretLairPromo instance = new SecretLairPromo(); - public static SecretLairShowdown getInstance() { + public static SecretLairPromo getInstance() { return instance; } - private SecretLairShowdown() { - super("Secret Lair Showdown", "SLP", ExpansionSet.buildDate(2023, 2, 17), SetType.PROMOTIONAL); + private SecretLairPromo() { + super("Secret Lair Promo", "SLP", ExpansionSet.buildDate(2023, 2, 17), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = true; @@ -32,6 +32,7 @@ public class SecretLairShowdown extends ExpansionSet { cards.add(new SetCardInfo("Fauna Shaman", 41, Rarity.RARE, mage.cards.f.FaunaShaman.class)); cards.add(new SetCardInfo("Flowerfoot Swordmaster", 46, Rarity.RARE, mage.cards.f.FlowerfootSwordmaster.class)); cards.add(new SetCardInfo("Force of Despair", 29, Rarity.RARE, mage.cards.f.ForceOfDespair.class, FULL_ART)); + cards.add(new SetCardInfo("Forest", 35, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Garruk Wildspeaker", 42, Rarity.MYTHIC, mage.cards.g.GarrukWildspeaker.class)); cards.add(new SetCardInfo("Goblin Guide", 23, Rarity.RARE, mage.cards.g.GoblinGuide.class)); cards.add(new SetCardInfo("Innkeeper's Talent", 45, Rarity.RARE, mage.cards.i.InnkeepersTalent.class, FULL_ART)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOfThePast.java b/Mage.Sets/src/mage/sets/ShadowsOfThePast.java index c84cbce0064..eb33e9a1bb4 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOfThePast.java +++ b/Mage.Sets/src/mage/sets/ShadowsOfThePast.java @@ -54,7 +54,6 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Forge Devil", 41, Rarity.COMMON, mage.cards.f.ForgeDevil.class)); cards.add(new SetCardInfo("Galvanic Juggernaut", 72, Rarity.UNCOMMON, mage.cards.g.GalvanicJuggernaut.class)); cards.add(new SetCardInfo("Garruk Relentless", 49, Rarity.MYTHIC, mage.cards.g.GarrukRelentless.class)); - cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 49, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class)); cards.add(new SetCardInfo("Geist of Saint Traft", 62, Rarity.MYTHIC, mage.cards.g.GeistOfSaintTraft.class)); cards.add(new SetCardInfo("Ghoulraiser", 30, Rarity.COMMON, mage.cards.g.Ghoulraiser.class)); cards.add(new SetCardInfo("Gnaw to the Bone", 50, Rarity.COMMON, mage.cards.g.GnawToTheBone.class)); @@ -64,14 +63,12 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Havengul Lich", 63, Rarity.MYTHIC, mage.cards.h.HavengulLich.class)); cards.add(new SetCardInfo("Havengul Runebinder", 16, Rarity.RARE, mage.cards.h.HavengulRunebinder.class)); cards.add(new SetCardInfo("Hollowhenge Scavenger", 52, Rarity.COMMON, mage.cards.h.HollowhengeScavenger.class)); - cards.add(new SetCardInfo("Howlpack Alpha", 53, Rarity.RARE, mage.cards.h.HowlpackAlpha.class)); cards.add(new SetCardInfo("Huntmaster of the Fells", 64, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class)); cards.add(new SetCardInfo("Immerwolf", 65, Rarity.UNCOMMON, mage.cards.i.Immerwolf.class)); cards.add(new SetCardInfo("Increasing Ambition", 32, Rarity.RARE, mage.cards.i.IncreasingAmbition.class)); cards.add(new SetCardInfo("Invisible Stalker", 17, Rarity.UNCOMMON, mage.cards.i.InvisibleStalker.class)); cards.add(new SetCardInfo("Kruin Outlaw", 42, Rarity.RARE, mage.cards.k.KruinOutlaw.class)); cards.add(new SetCardInfo("Lingering Souls", 9, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class)); - cards.add(new SetCardInfo("Lord of Lineage", 27, Rarity.MYTHIC, mage.cards.l.LordOfLineage.class)); cards.add(new SetCardInfo("Mayor of Avabruck", 53, Rarity.RARE, mage.cards.m.MayorOfAvabruck.class)); cards.add(new SetCardInfo("Mist Raven", 18, Rarity.COMMON, mage.cards.m.MistRaven.class)); cards.add(new SetCardInfo("Moonmist", 54, Rarity.COMMON, mage.cards.m.Moonmist.class)); @@ -79,7 +76,6 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Mystic Retrieval", 20, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class)); cards.add(new SetCardInfo("Past in Flames", 43, Rarity.MYTHIC, mage.cards.p.PastInFlames.class)); cards.add(new SetCardInfo("Rally the Peasants", 10, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class)); - cards.add(new SetCardInfo("Ravager of the Fells", 64, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class)); cards.add(new SetCardInfo("Requiem Angel", 11, Rarity.RARE, mage.cards.r.RequiemAngel.class)); cards.add(new SetCardInfo("Seance", 12, Rarity.UNCOMMON, mage.cards.s.Seance.class)); cards.add(new SetCardInfo("Selhoff Occultist", 21, Rarity.COMMON, mage.cards.s.SelhoffOccultist.class)); @@ -93,7 +89,6 @@ public class ShadowsOfThePast extends ExpansionSet { cards.add(new SetCardInfo("Spider Spawning", 56, Rarity.UNCOMMON, mage.cards.s.SpiderSpawning.class)); cards.add(new SetCardInfo("Stitcher's Apprentice", 24, Rarity.COMMON, mage.cards.s.StitchersApprentice.class)); cards.add(new SetCardInfo("Stromkirk Captain", 67, Rarity.UNCOMMON, mage.cards.s.StromkirkCaptain.class)); - cards.add(new SetCardInfo("Terror of Kruin Pass", 42, Rarity.RARE, mage.cards.t.TerrorOfKruinPass.class)); cards.add(new SetCardInfo("Tragic Slip", 35, Rarity.COMMON, mage.cards.t.TragicSlip.class)); cards.add(new SetCardInfo("Traitorous Blood", 45, Rarity.COMMON, mage.cards.t.TraitorousBlood.class)); cards.add(new SetCardInfo("Travel Preparations", 57, Rarity.COMMON, mage.cards.t.TravelPreparations.class)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java index bd1e36b3394..f475231ccc2 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java @@ -43,29 +43,22 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Alms of the Vein", 98, Rarity.COMMON, mage.cards.a.AlmsOfTheVein.class)); cards.add(new SetCardInfo("Altered Ego", 241, Rarity.RARE, mage.cards.a.AlteredEgo.class)); cards.add(new SetCardInfo("Always Watching", 1, Rarity.RARE, mage.cards.a.AlwaysWatching.class)); - cards.add(new SetCardInfo("Ancient of the Equinox", 194, Rarity.UNCOMMON, mage.cards.a.AncientOfTheEquinox.class)); cards.add(new SetCardInfo("Angel of Deliverance", 2, Rarity.RARE, mage.cards.a.AngelOfDeliverance.class)); cards.add(new SetCardInfo("Angelic Purge", 3, Rarity.COMMON, mage.cards.a.AngelicPurge.class)); cards.add(new SetCardInfo("Anguished Unmaking", 242, Rarity.RARE, mage.cards.a.AnguishedUnmaking.class)); cards.add(new SetCardInfo("Apothecary Geist", 4, Rarity.COMMON, mage.cards.a.ApothecaryGeist.class)); cards.add(new SetCardInfo("Archangel Avacyn", 5, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", 243, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 243, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); - cards.add(new SetCardInfo("Ashmouth Blade", 260, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class)); cards.add(new SetCardInfo("Asylum Visitor", 99, Rarity.RARE, mage.cards.a.AsylumVisitor.class)); cards.add(new SetCardInfo("Autumnal Gloom", 194, Rarity.UNCOMMON, mage.cards.a.AutumnalGloom.class)); cards.add(new SetCardInfo("Avacyn's Judgment", 145, Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 5, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); cards.add(new SetCardInfo("Avacynian Missionaries", 6, Rarity.UNCOMMON, mage.cards.a.AvacynianMissionaries.class)); - cards.add(new SetCardInfo("Awoken Horror", 92, Rarity.RARE, mage.cards.a.AwokenHorror.class)); - cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 54, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class)); cards.add(new SetCardInfo("Behind the Scenes", 100, Rarity.UNCOMMON, mage.cards.b.BehindTheScenes.class)); cards.add(new SetCardInfo("Behold the Beyond", 101, Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class)); cards.add(new SetCardInfo("Biting Rain", 102, Rarity.UNCOMMON, mage.cards.b.BitingRain.class)); cards.add(new SetCardInfo("Bloodmad Vampire", 146, Rarity.COMMON, mage.cards.b.BloodmadVampire.class)); cards.add(new SetCardInfo("Bound by Moonsilver", 7, Rarity.UNCOMMON, mage.cards.b.BoundByMoonsilver.class)); cards.add(new SetCardInfo("Brain in a Jar", 252, Rarity.RARE, mage.cards.b.BrainInAJar.class)); - cards.add(new SetCardInfo("Branded Howler", 149, Rarity.COMMON, mage.cards.b.BrandedHowler.class)); cards.add(new SetCardInfo("Breakneck Rider", 147, Rarity.UNCOMMON, mage.cards.b.BreakneckRider.class)); cards.add(new SetCardInfo("Briarbridge Patrol", 195, Rarity.UNCOMMON, mage.cards.b.BriarbridgePatrol.class)); cards.add(new SetCardInfo("Broken Concentration", 50, Rarity.UNCOMMON, mage.cards.b.BrokenConcentration.class)); @@ -94,7 +87,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Dead Weight", 106, Rarity.COMMON, mage.cards.d.DeadWeight.class)); cards.add(new SetCardInfo("Deathcap Cultivator", 202, Rarity.RARE, mage.cards.d.DeathcapCultivator.class)); cards.add(new SetCardInfo("Declaration in Stone", 12, Rarity.RARE, mage.cards.d.DeclarationInStone.class)); - cards.add(new SetCardInfo("Demon-Possessed Witch", 119, Rarity.UNCOMMON, mage.cards.d.DemonPossessedWitch.class)); cards.add(new SetCardInfo("Deny Existence", 55, Rarity.COMMON, mage.cards.d.DenyExistence.class)); cards.add(new SetCardInfo("Descend upon the Sinful", 13, Rarity.MYTHIC, mage.cards.d.DescendUponTheSinful.class)); cards.add(new SetCardInfo("Devils' Playground", 151, Rarity.RARE, mage.cards.d.DevilsPlayground.class)); @@ -126,7 +118,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Fevered Visions", 244, Rarity.RARE, mage.cards.f.FeveredVisions.class)); cards.add(new SetCardInfo("Fiery Temper", 156, Rarity.COMMON, mage.cards.f.FieryTemper.class)); cards.add(new SetCardInfo("Flameblade Angel", 157, Rarity.RARE, mage.cards.f.FlamebladeAngel.class)); - cards.add(new SetCardInfo("Flameheart Werewolf", 169, Rarity.UNCOMMON, mage.cards.f.FlameheartWerewolf.class)); cards.add(new SetCardInfo("Fleeting Memories", 62, Rarity.UNCOMMON, mage.cards.f.FleetingMemories.class)); cards.add(new SetCardInfo("Foreboding Ruins", 272, Rarity.RARE, mage.cards.f.ForebodingRuins.class)); cards.add(new SetCardInfo("Forest", 295, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); @@ -141,7 +132,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Furtive Homunculus", 64, Rarity.COMMON, mage.cards.f.FurtiveHomunculus.class)); cards.add(new SetCardInfo("Game Trail", 276, Rarity.RARE, mage.cards.g.GameTrail.class)); cards.add(new SetCardInfo("Gatstaf Arsonists", 158, Rarity.COMMON, mage.cards.g.GatstafArsonists.class)); - cards.add(new SetCardInfo("Gatstaf Ravagers", 158, Rarity.COMMON, mage.cards.g.GatstafRavagers.class)); cards.add(new SetCardInfo("Geier Reach Bandit", 159, Rarity.RARE, mage.cards.g.GeierReachBandit.class)); cards.add(new SetCardInfo("Geistblast", 160, Rarity.UNCOMMON, mage.cards.g.Geistblast.class)); cards.add(new SetCardInfo("Geralf's Masterpiece", 65, Rarity.MYTHIC, mage.cards.g.GeralfsMasterpiece.class)); @@ -162,7 +152,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Harvest Hand", 256, Rarity.UNCOMMON, mage.cards.h.HarvestHand.class)); cards.add(new SetCardInfo("Haunted Cloak", 257, Rarity.UNCOMMON, mage.cards.h.HauntedCloak.class)); cards.add(new SetCardInfo("Heir of Falkenrath", 116, Rarity.UNCOMMON, mage.cards.h.HeirOfFalkenrath.class)); - cards.add(new SetCardInfo("Heir to the Night", 116, Rarity.UNCOMMON, mage.cards.h.HeirToTheNight.class)); cards.add(new SetCardInfo("Hermit of the Natterknolls", 209, Rarity.UNCOMMON, mage.cards.h.HermitOfTheNatterknolls.class)); cards.add(new SetCardInfo("Highland Lake", 277, Rarity.UNCOMMON, mage.cards.h.HighlandLake.class)); cards.add(new SetCardInfo("Hinterland Logger", 210, Rarity.COMMON, mage.cards.h.HinterlandLogger.class)); @@ -172,14 +161,11 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Howlpack Wolf", 164, Rarity.COMMON, mage.cards.h.HowlpackWolf.class)); cards.add(new SetCardInfo("Hulking Devil", 165, Rarity.COMMON, mage.cards.h.HulkingDevil.class)); cards.add(new SetCardInfo("Humble the Brute", 23, Rarity.UNCOMMON, mage.cards.h.HumbleTheBrute.class)); - cards.add(new SetCardInfo("Incited Rabble", 46, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class)); cards.add(new SetCardInfo("Incorrigible Youths", 166, Rarity.UNCOMMON, mage.cards.i.IncorrigibleYouths.class)); cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class)); cards.add(new SetCardInfo("Inexorable Blob", 212, Rarity.RARE, mage.cards.i.InexorableBlob.class)); - cards.add(new SetCardInfo("Infectious Curse", 97, Rarity.UNCOMMON, mage.cards.i.InfectiousCurse.class)); cards.add(new SetCardInfo("Inner Struggle", 167, Rarity.UNCOMMON, mage.cards.i.InnerStruggle.class)); cards.add(new SetCardInfo("Inquisitor's Ox", 24, Rarity.COMMON, mage.cards.i.InquisitorsOx.class)); - cards.add(new SetCardInfo("Insidious Mist", 108, Rarity.RARE, mage.cards.i.InsidiousMist.class)); cards.add(new SetCardInfo("Insolent Neonate", 168, Rarity.COMMON, mage.cards.i.InsolentNeonate.class)); cards.add(new SetCardInfo("Inspiring Captain", 25, Rarity.COMMON, mage.cards.i.InspiringCaptain.class)); cards.add(new SetCardInfo("Intrepid Provisioner", 213, Rarity.COMMON, mage.cards.i.IntrepidProvisioner.class)); @@ -194,15 +180,11 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Kessig Dire Swine", 214, Rarity.COMMON, mage.cards.k.KessigDireSwine.class)); cards.add(new SetCardInfo("Kessig Forgemaster", 169, Rarity.UNCOMMON, mage.cards.k.KessigForgemaster.class)); cards.add(new SetCardInfo("Kindly Stranger", 119, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class)); - cards.add(new SetCardInfo("Krallenhorde Howler", 203, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class)); - cards.add(new SetCardInfo("Lambholt Butcher", 215, Rarity.UNCOMMON, mage.cards.l.LambholtButcher.class)); cards.add(new SetCardInfo("Lambholt Pacifist", 215, Rarity.UNCOMMON, mage.cards.l.LambholtPacifist.class)); cards.add(new SetCardInfo("Lamplighter of Selhoff", 72, Rarity.COMMON, mage.cards.l.LamplighterOfSelhoff.class)); cards.add(new SetCardInfo("Lightning Axe", 170, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class)); cards.add(new SetCardInfo("Liliana's Indignation", 120, Rarity.UNCOMMON, mage.cards.l.LilianasIndignation.class)); cards.add(new SetCardInfo("Loam Dryad", 216, Rarity.COMMON, mage.cards.l.LoamDryad.class)); - cards.add(new SetCardInfo("Lone Wolf of the Natterknolls", 209, Rarity.UNCOMMON, mage.cards.l.LoneWolfOfTheNatterknolls.class)); - cards.add(new SetCardInfo("Lunarch Inquisitors", 6, Rarity.UNCOMMON, mage.cards.l.LunarchInquisitors.class)); cards.add(new SetCardInfo("Macabre Waltz", 121, Rarity.COMMON, mage.cards.m.MacabreWaltz.class)); cards.add(new SetCardInfo("Mad Prophet", 171, Rarity.UNCOMMON, mage.cards.m.MadProphet.class)); cards.add(new SetCardInfo("Magmatic Chasm", 172, Rarity.COMMON, mage.cards.m.MagmaticChasm.class)); @@ -216,7 +198,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Mindwrack Demon", 124, Rarity.MYTHIC, mage.cards.m.MindwrackDemon.class)); cards.add(new SetCardInfo("Moldgraf Scavenger", 218, Rarity.COMMON, mage.cards.m.MoldgrafScavenger.class)); cards.add(new SetCardInfo("Moonlight Hunt", 219, Rarity.UNCOMMON, mage.cards.m.MoonlightHunt.class)); - cards.add(new SetCardInfo("Moonrise Intruder", 190, Rarity.UNCOMMON, mage.cards.m.MoonriseIntruder.class)); cards.add(new SetCardInfo("Moorland Drifter", 27, Rarity.COMMON, mage.cards.m.MoorlandDrifter.class)); cards.add(new SetCardInfo("Morkrut Necropod", 125, Rarity.UNCOMMON, mage.cards.m.MorkrutNecropod.class)); cards.add(new SetCardInfo("Mountain", 292, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -228,7 +209,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Nahiri's Machinations", 28, Rarity.UNCOMMON, mage.cards.n.NahirisMachinations.class)); cards.add(new SetCardInfo("Nahiri, the Harbinger", 247, Rarity.MYTHIC, mage.cards.n.NahiriTheHarbinger.class)); cards.add(new SetCardInfo("Nearheath Chaplain", 29, Rarity.UNCOMMON, mage.cards.n.NearheathChaplain.class)); - cards.add(new SetCardInfo("Neck Breaker", 147, Rarity.UNCOMMON, mage.cards.n.NeckBreaker.class)); cards.add(new SetCardInfo("Neglected Heirloom", 260, Rarity.UNCOMMON, mage.cards.n.NeglectedHeirloom.class)); cards.add(new SetCardInfo("Nephalia Moondrakes", 75, Rarity.RARE, mage.cards.n.NephaliaMoondrakes.class)); cards.add(new SetCardInfo("Niblis of Dusk", 76, Rarity.COMMON, mage.cards.n.NiblisOfDusk.class)); @@ -237,15 +217,11 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Odric, Lunarch Marshal", 31, Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class)); cards.add(new SetCardInfo("Olivia's Bloodsworn", 127, Rarity.UNCOMMON, mage.cards.o.OliviasBloodsworn.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", 248, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class)); - cards.add(new SetCardInfo("One of the Pack", 229, Rarity.COMMON, mage.cards.o.OneOfThePack.class)); cards.add(new SetCardInfo("Ongoing Investigation", 77, Rarity.UNCOMMON, mage.cards.o.OngoingInvestigation.class)); cards.add(new SetCardInfo("Open the Armory", 32, Rarity.UNCOMMON, mage.cards.o.OpenTheArmory.class)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 281, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class)); cards.add(new SetCardInfo("Pack Guardian", 221, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class)); cards.add(new SetCardInfo("Pale Rider of Trostad", 128, Rarity.UNCOMMON, mage.cards.p.PaleRiderOfTrostad.class)); cards.add(new SetCardInfo("Paranoid Parish-Blade", 33, Rarity.UNCOMMON, mage.cards.p.ParanoidParishBlade.class)); - cards.add(new SetCardInfo("Perfected Form", 49, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class)); - cards.add(new SetCardInfo("Persistent Nightmare", 88, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class)); cards.add(new SetCardInfo("Pieces of the Puzzle", 78, Rarity.COMMON, mage.cards.p.PiecesOfThePuzzle.class)); cards.add(new SetCardInfo("Pious Evangel", 34, Rarity.UNCOMMON, mage.cards.p.PiousEvangel.class)); @@ -276,7 +252,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Sanguinary Mage", 178, Rarity.COMMON, mage.cards.s.SanguinaryMage.class)); cards.add(new SetCardInfo("Sanitarium Skeleton", 133, Rarity.COMMON, mage.cards.s.SanitariumSkeleton.class)); cards.add(new SetCardInfo("Scourge Wolf", 179, Rarity.RARE, mage.cards.s.ScourgeWolf.class)); - cards.add(new SetCardInfo("Scrounged Scythe", 256, Rarity.UNCOMMON, mage.cards.s.ScroungedScythe.class)); cards.add(new SetCardInfo("Seagraf Skaab", 84, Rarity.COMMON, mage.cards.s.SeagrafSkaab.class)); cards.add(new SetCardInfo("Seasons Past", 226, Rarity.MYTHIC, mage.cards.s.SeasonsPast.class)); cards.add(new SetCardInfo("Second Harvest", 227, Rarity.RARE, mage.cards.s.SecondHarvest.class)); @@ -292,7 +267,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Sinister Concoction", 135, Rarity.UNCOMMON, mage.cards.s.SinisterConcoction.class)); cards.add(new SetCardInfo("Skeleton Key", 263, Rarity.UNCOMMON, mage.cards.s.SkeletonKey.class)); cards.add(new SetCardInfo("Skin Invasion", 182, Rarity.UNCOMMON, mage.cards.s.SkinInvasion.class)); - cards.add(new SetCardInfo("Skin Shedder", 182, Rarity.UNCOMMON, mage.cards.s.SkinShedder.class)); cards.add(new SetCardInfo("Slayer's Plate", 264, Rarity.RARE, mage.cards.s.SlayersPlate.class)); cards.add(new SetCardInfo("Sleep Paralysis", 87, Rarity.COMMON, mage.cards.s.SleepParalysis.class)); cards.add(new SetCardInfo("Solitary Hunter", 229, Rarity.COMMON, mage.cards.s.SolitaryHunter.class)); @@ -308,7 +282,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Stitchwing Skaab", 90, Rarity.UNCOMMON, mage.cards.s.StitchwingSkaab.class)); cards.add(new SetCardInfo("Stoic Builder", 231, Rarity.COMMON, mage.cards.s.StoicBuilder.class)); cards.add(new SetCardInfo("Stone Quarry", 279, Rarity.UNCOMMON, mage.cards.s.StoneQuarry.class)); - cards.add(new SetCardInfo("Stonewing Antagonizer", 266, Rarity.UNCOMMON, mage.cards.s.StonewingAntagonizer.class)); cards.add(new SetCardInfo("Stormrider Spirit", 91, Rarity.COMMON, mage.cards.s.StormriderSpirit.class)); cards.add(new SetCardInfo("Strength of Arms", 40, Rarity.COMMON, mage.cards.s.StrengthOfArms.class)); cards.add(new SetCardInfo("Stromkirk Mentor", 137, Rarity.COMMON, mage.cards.s.StromkirkMentor.class)); @@ -331,7 +304,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Thraben Gargoyle", 266, Rarity.UNCOMMON, mage.cards.t.ThrabenGargoyle.class)); cards.add(new SetCardInfo("Thraben Inspector", 44, Rarity.COMMON, mage.cards.t.ThrabenInspector.class)); cards.add(new SetCardInfo("Throttle", 138, Rarity.COMMON, mage.cards.t.Throttle.class)); - cards.add(new SetCardInfo("Timber Shredder", 210, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 233, Rarity.RARE, mage.cards.t.TirelessTracker.class)); cards.add(new SetCardInfo("To the Slaughter", 139, Rarity.RARE, mage.cards.t.ToTheSlaughter.class)); cards.add(new SetCardInfo("Tooth Collector", 140, Rarity.UNCOMMON, mage.cards.t.ToothCollector.class)); @@ -347,7 +319,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Ulvenwald Hydra", 235, Rarity.MYTHIC, mage.cards.u.UlvenwaldHydra.class)); cards.add(new SetCardInfo("Ulvenwald Mysteries", 236, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class)); cards.add(new SetCardInfo("Uncaged Fury", 188, Rarity.COMMON, mage.cards.u.UncagedFury.class)); - cards.add(new SetCardInfo("Unimpeded Trespasser", 94, Rarity.UNCOMMON, mage.cards.u.UnimpededTrespasser.class)); cards.add(new SetCardInfo("Uninvited Geist", 94, Rarity.UNCOMMON, mage.cards.u.UninvitedGeist.class)); cards.add(new SetCardInfo("Unruly Mob", 47, Rarity.COMMON, mage.cards.u.UnrulyMob.class)); cards.add(new SetCardInfo("Vampire Noble", 143, Rarity.COMMON, mage.cards.v.VampireNoble.class)); @@ -357,17 +328,13 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Vessel of Paramnesia", 95, Rarity.COMMON, mage.cards.v.VesselOfParamnesia.class)); cards.add(new SetCardInfo("Vessel of Volatility", 189, Rarity.COMMON, mage.cards.v.VesselOfVolatility.class)); cards.add(new SetCardInfo("Veteran Cathar", 238, Rarity.UNCOMMON, mage.cards.v.VeteranCathar.class)); - cards.add(new SetCardInfo("Vildin-Pack Alpha", 159, Rarity.RARE, mage.cards.v.VildinPackAlpha.class)); cards.add(new SetCardInfo("Village Messenger", 190, Rarity.UNCOMMON, mage.cards.v.VillageMessenger.class)); cards.add(new SetCardInfo("Voldaren Duelist", 191, Rarity.COMMON, mage.cards.v.VoldarenDuelist.class)); cards.add(new SetCardInfo("Warped Landscape", 280, Rarity.COMMON, mage.cards.w.WarpedLandscape.class)); cards.add(new SetCardInfo("Watcher in the Web", 239, Rarity.COMMON, mage.cards.w.WatcherInTheWeb.class)); - cards.add(new SetCardInfo("Wayward Disciple", 34, Rarity.UNCOMMON, mage.cards.w.WaywardDisciple.class)); cards.add(new SetCardInfo("Weirding Wood", 240, Rarity.UNCOMMON, mage.cards.w.WeirdingWood.class)); cards.add(new SetCardInfo("Welcome to the Fold", 96, Rarity.RARE, mage.cards.w.WelcomeToTheFold.class)); - cards.add(new SetCardInfo("Werewolf of Ancient Hunger", 225, Rarity.RARE, mage.cards.w.WerewolfOfAncientHunger.class)); cards.add(new SetCardInfo("Westvale Abbey", 281, Rarity.RARE, mage.cards.w.WestvaleAbbey.class)); - cards.add(new SetCardInfo("Westvale Cult Leader", 21, Rarity.RARE, mage.cards.w.WestvaleCultLeader.class)); cards.add(new SetCardInfo("Wicker Witch", 268, Rarity.COMMON, mage.cards.w.WickerWitch.class)); cards.add(new SetCardInfo("Wild-Field Scarecrow", 269, Rarity.UNCOMMON, mage.cards.w.WildFieldScarecrow.class)); cards.add(new SetCardInfo("Wolf of Devil's Breach", 192, Rarity.MYTHIC, mage.cards.w.WolfOfDevilsBreach.class)); diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java index 8c445e2fa97..02d295c4b5e 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistradPromos.java @@ -29,11 +29,8 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Anguished Unmaking", 242, Rarity.RARE, mage.cards.a.AnguishedUnmaking.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Archangel Avacyn", "5s", Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); cards.add(new SetCardInfo("Asylum Visitor", "99s", Rarity.RARE, mage.cards.a.AsylumVisitor.class)); cards.add(new SetCardInfo("Avacyn's Judgment", "145s", Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", "5s", Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); - cards.add(new SetCardInfo("Awoken Horror", "92s", Rarity.RARE, mage.cards.a.AwokenHorror.class)); cards.add(new SetCardInfo("Behold the Beyond", "101s", Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class)); cards.add(new SetCardInfo("Brain in a Jar", "252s", Rarity.RARE, mage.cards.b.BrainInAJar.class)); cards.add(new SetCardInfo("Burn from Within", "148s", Rarity.RARE, mage.cards.b.BurnFromWithin.class)); @@ -73,8 +70,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Harness the Storm", "163s", Rarity.RARE, mage.cards.h.HarnessTheStorm.class)); cards.add(new SetCardInfo("Incorrigible Youths", 166, Rarity.UNCOMMON, mage.cards.i.IncorrigibleYouths.class)); cards.add(new SetCardInfo("Inexorable Blob", "212s", Rarity.RARE, mage.cards.i.InexorableBlob.class)); - cards.add(new SetCardInfo("Insidious Mist", "108s", Rarity.RARE, mage.cards.i.InsidiousMist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Insidious Mist", 108, Rarity.RARE, mage.cards.i.InsidiousMist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Invocation of Saint Traft", "246s", Rarity.RARE, mage.cards.i.InvocationOfSaintTraft.class)); cards.add(new SetCardInfo("Jace, Unraveler of Secrets", "69s", Rarity.MYTHIC, mage.cards.j.JaceUnravelerOfSecrets.class)); cards.add(new SetCardInfo("Markov Dreadknight", "122s", Rarity.RARE, mage.cards.m.MarkovDreadknight.class, NON_FULL_USE_VARIOUS)); @@ -85,8 +80,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Nephalia Moondrakes", 75, Rarity.RARE, mage.cards.n.NephaliaMoondrakes.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Odric, Lunarch Marshal", "31s", Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", "248s", Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", "281s", Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class)); - cards.add(new SetCardInfo("Persistent Nightmare", "88s", Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Port Town", "278s", Rarity.RARE, mage.cards.p.PortTown.class)); cards.add(new SetCardInfo("Prized Amalgam", "249s", Rarity.RARE, mage.cards.p.PrizedAmalgam.class)); cards.add(new SetCardInfo("Rattlechains", "81s", Rarity.RARE, mage.cards.r.Rattlechains.class)); @@ -114,11 +107,8 @@ public class ShadowsOverInnistradPromos extends ExpansionSet { cards.add(new SetCardInfo("Traverse the Ulvenwald", "234s", Rarity.RARE, mage.cards.t.TraverseTheUlvenwald.class)); cards.add(new SetCardInfo("Triskaidekaphobia", "141s", Rarity.RARE, mage.cards.t.Triskaidekaphobia.class)); cards.add(new SetCardInfo("Ulvenwald Hydra", "235s", Rarity.MYTHIC, mage.cards.u.UlvenwaldHydra.class)); - cards.add(new SetCardInfo("Vildin-Pack Alpha", "159s", Rarity.RARE, mage.cards.v.VildinPackAlpha.class)); cards.add(new SetCardInfo("Welcome to the Fold", "96s", Rarity.RARE, mage.cards.w.WelcomeToTheFold.class)); - cards.add(new SetCardInfo("Werewolf of Ancient Hunger", "225s", Rarity.RARE, mage.cards.w.WerewolfOfAncientHunger.class)); cards.add(new SetCardInfo("Westvale Abbey", "281s", Rarity.RARE, mage.cards.w.WestvaleAbbey.class)); - cards.add(new SetCardInfo("Westvale Cult Leader", "21s", Rarity.RARE, mage.cards.w.WestvaleCultLeader.class)); cards.add(new SetCardInfo("Wolf of Devil's Breach", "192s", Rarity.MYTHIC, mage.cards.w.WolfOfDevilsBreach.class)); } } diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java index 8739ee9b6ea..beae6f1be95 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistradRemastered.java @@ -25,7 +25,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { // TODO: implement special slot with x1 card from SIS - Shadows of the Past // https://mtg.fandom.com/wiki/Shadows_over_Innistrad_Remastered/Shadows_of_the_Past - cards.add(new SetCardInfo("Abolisher of Bloodlines", 138, Rarity.RARE, mage.cards.a.AbolisherOfBloodlines.class)); cards.add(new SetCardInfo("Abundant Maw", 1, Rarity.UNCOMMON, mage.cards.a.AbundantMaw.class)); cards.add(new SetCardInfo("Accursed Witch", 97, Rarity.UNCOMMON, mage.cards.a.AccursedWitch.class)); cards.add(new SetCardInfo("Advanced Stitchwing", 54, Rarity.UNCOMMON, mage.cards.a.AdvancedStitchwing.class)); @@ -39,14 +38,8 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Apothecary Geist", 12, Rarity.COMMON, mage.cards.a.ApothecaryGeist.class)); cards.add(new SetCardInfo("Archangel Avacyn", 13, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class)); cards.add(new SetCardInfo("Arlinn Kord", 230, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class)); - cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", 230, Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class)); - cards.add(new SetCardInfo("Ashmouth Blade", 256, Rarity.UNCOMMON, mage.cards.a.AshmouthBlade.class)); cards.add(new SetCardInfo("Assembled Alphas", 141, Rarity.RARE, mage.cards.a.AssembledAlphas.class)); - cards.add(new SetCardInfo("Aurora of Emrakul", 248, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class)); cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); - cards.add(new SetCardInfo("Avacyn, the Purifier", 13, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class)); - cards.add(new SetCardInfo("Awoken Horror", 95, Rarity.RARE, mage.cards.a.AwokenHorror.class)); - cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 59, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class)); cards.add(new SetCardInfo("Bedlam Reveler", 143, Rarity.RARE, mage.cards.b.BedlamReveler.class)); cards.add(new SetCardInfo("Biting Rain", 99, Rarity.UNCOMMON, mage.cards.b.BitingRain.class)); cards.add(new SetCardInfo("Blessed Alliance", 14, Rarity.UNCOMMON, mage.cards.b.BlessedAlliance.class)); @@ -74,7 +67,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Collective Defiance", 148, Rarity.RARE, mage.cards.c.CollectiveDefiance.class)); cards.add(new SetCardInfo("Collective Effort", 19, Rarity.RARE, mage.cards.c.CollectiveEffort.class)); cards.add(new SetCardInfo("Compelling Deterrence", 55, Rarity.UNCOMMON, mage.cards.c.CompellingDeterrence.class)); - cards.add(new SetCardInfo("Conduit of Emrakul", 149, Rarity.COMMON, mage.cards.c.ConduitOfEmrakul.class)); cards.add(new SetCardInfo("Conduit of Storms", 149, Rarity.COMMON, mage.cards.c.ConduitOfStorms.class)); cards.add(new SetCardInfo("Confirm Suspicions", 56, Rarity.RARE, mage.cards.c.ConfirmSuspicions.class)); cards.add(new SetCardInfo("Confront the Unknown", 190, Rarity.COMMON, mage.cards.c.ConfrontTheUnknown.class)); @@ -93,7 +85,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Deathcap Cultivator", 193, Rarity.UNCOMMON, mage.cards.d.DeathcapCultivator.class)); cards.add(new SetCardInfo("Decimator of the Provinces", 2, Rarity.MYTHIC, mage.cards.d.DecimatorOfTheProvinces.class)); cards.add(new SetCardInfo("Declaration in Stone", 23, Rarity.RARE, mage.cards.d.DeclarationInStone.class)); - cards.add(new SetCardInfo("Demon-Possessed Witch", 107, Rarity.UNCOMMON, mage.cards.d.DemonPossessedWitch.class)); cards.add(new SetCardInfo("Deny Existence", 60, Rarity.COMMON, mage.cards.d.DenyExistence.class)); cards.add(new SetCardInfo("Deranged Whelp", 150, Rarity.COMMON, mage.cards.d.DerangedWhelp.class)); cards.add(new SetCardInfo("Descend upon the Sinful", 24, Rarity.MYTHIC, mage.cards.d.DescendUponTheSinful.class)); @@ -128,7 +119,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Field Creeper", 251, Rarity.COMMON, mage.cards.f.FieldCreeper.class)); cards.add(new SetCardInfo("Fiend Binder", 29, Rarity.COMMON, mage.cards.f.FiendBinder.class)); cards.add(new SetCardInfo("Fiery Temper", 154, Rarity.UNCOMMON, mage.cards.f.FieryTemper.class)); - cards.add(new SetCardInfo("Final Iteration", 61, Rarity.RARE, mage.cards.f.FinalIteration.class)); cards.add(new SetCardInfo("Flameblade Angel", 155, Rarity.RARE, mage.cards.f.FlamebladeAngel.class)); cards.add(new SetCardInfo("Fleeting Memories", 69, Rarity.UNCOMMON, mage.cards.f.FleetingMemories.class)); cards.add(new SetCardInfo("Fogwalker", 70, Rarity.COMMON, mage.cards.f.Fogwalker.class)); @@ -144,7 +134,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Galvanic Bombardment", 157, Rarity.COMMON, mage.cards.g.GalvanicBombardment.class)); cards.add(new SetCardInfo("Game Trail", 269, Rarity.UNCOMMON, mage.cards.g.GameTrail.class)); cards.add(new SetCardInfo("Gatstaf Arsonists", 158, Rarity.COMMON, mage.cards.g.GatstafArsonists.class)); - cards.add(new SetCardInfo("Gatstaf Ravagers", 158, Rarity.COMMON, mage.cards.g.GatstafRavagers.class)); cards.add(new SetCardInfo("Gavony Unhallowed", 111, Rarity.COMMON, mage.cards.g.GavonyUnhallowed.class)); cards.add(new SetCardInfo("Geier Reach Bandit", 159, Rarity.UNCOMMON, mage.cards.g.GeierReachBandit.class)); cards.add(new SetCardInfo("Geier Reach Sanitarium", 270, Rarity.RARE, mage.cards.g.GeierReachSanitarium.class)); @@ -175,15 +164,12 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Highland Lake", 272, Rarity.UNCOMMON, mage.cards.h.HighlandLake.class)); cards.add(new SetCardInfo("Hinterland Logger", 201, Rarity.COMMON, mage.cards.h.HinterlandLogger.class)); cards.add(new SetCardInfo("Hope Against Hope", 33, Rarity.UNCOMMON, mage.cards.h.HopeAgainstHope.class)); - cards.add(new SetCardInfo("Howling Chorus", 214, Rarity.UNCOMMON, mage.cards.h.HowlingChorus.class)); cards.add(new SetCardInfo("Howlpack Resurgence", 202, Rarity.UNCOMMON, mage.cards.h.HowlpackResurgence.class)); cards.add(new SetCardInfo("Howlpack Wolf", 162, Rarity.COMMON, mage.cards.h.HowlpackWolf.class)); cards.add(new SetCardInfo("Humble the Brute", 34, Rarity.UNCOMMON, mage.cards.h.HumbleTheBrute.class)); cards.add(new SetCardInfo("Imprisoned in the Moon", 74, Rarity.COMMON, mage.cards.i.ImprisonedInTheMoon.class)); cards.add(new SetCardInfo("Incendiary Flow", 163, Rarity.COMMON, mage.cards.i.IncendiaryFlow.class)); - cards.add(new SetCardInfo("Incited Rabble", 53, Rarity.UNCOMMON, mage.cards.i.IncitedRabble.class)); cards.add(new SetCardInfo("Indulgent Aristocrat", 118, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class)); - cards.add(new SetCardInfo("Infectious Curse", 97, Rarity.UNCOMMON, mage.cards.i.InfectiousCurse.class)); cards.add(new SetCardInfo("Ingenious Skaab", 75, Rarity.COMMON, mage.cards.i.IngeniousSkaab.class)); cards.add(new SetCardInfo("Insatiable Gorgers", 164, Rarity.COMMON, mage.cards.i.InsatiableGorgers.class)); cards.add(new SetCardInfo("Insolent Neonate", 165, Rarity.COMMON, mage.cards.i.InsolentNeonate.class)); @@ -194,11 +180,9 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Island", 280, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 281, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 282, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("It That Rides as One", 36, Rarity.UNCOMMON, mage.cards.i.ItThatRidesAsOne.class)); cards.add(new SetCardInfo("Jace's Scrutiny", 78, Rarity.COMMON, mage.cards.j.JacesScrutiny.class)); cards.add(new SetCardInfo("Jace, Unraveler of Secrets", 77, Rarity.MYTHIC, mage.cards.j.JaceUnravelerOfSecrets.class)); cards.add(new SetCardInfo("Kindly Stranger", 107, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class)); - cards.add(new SetCardInfo("Krallenhorde Howler", 194, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class)); cards.add(new SetCardInfo("Laboratory Brute", 79, Rarity.COMMON, mage.cards.l.LaboratoryBrute.class)); cards.add(new SetCardInfo("Lightning Axe", 166, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class)); cards.add(new SetCardInfo("Liliana's Elite", 120, Rarity.COMMON, mage.cards.l.LilianasElite.class)); @@ -221,7 +205,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Mirrorwing Dragon", 170, Rarity.MYTHIC, mage.cards.m.MirrorwingDragon.class)); cards.add(new SetCardInfo("Mockery of Nature", 8, Rarity.UNCOMMON, mage.cards.m.MockeryOfNature.class)); cards.add(new SetCardInfo("Moonlight Hunt", 205, Rarity.COMMON, mage.cards.m.MoonlightHunt.class)); - cards.add(new SetCardInfo("Moonrise Intruder", 184, Rarity.UNCOMMON, mage.cards.m.MoonriseIntruder.class)); cards.add(new SetCardInfo("Morkrut Necropod", 125, Rarity.COMMON, mage.cards.m.MorkrutNecropod.class)); cards.add(new SetCardInfo("Mountain", 286, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 287, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); @@ -241,10 +224,8 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Olivia's Dragoon", 128, Rarity.COMMON, mage.cards.o.OliviasDragoon.class)); cards.add(new SetCardInfo("Olivia, Mobilized for War", 239, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class)); cards.add(new SetCardInfo("Ongoing Investigation", 84, Rarity.UNCOMMON, mage.cards.o.OngoingInvestigation.class)); - cards.add(new SetCardInfo("Ormendahl, Profane Prince", 275, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class)); cards.add(new SetCardInfo("Pack Guardian", 208, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class)); cards.add(new SetCardInfo("Permeating Mass", 209, Rarity.RARE, mage.cards.p.PermeatingMass.class)); - cards.add(new SetCardInfo("Persistent Nightmare", 90, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class)); cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class)); cards.add(new SetCardInfo("Pieces of the Puzzle", 85, Rarity.UNCOMMON, mage.cards.p.PiecesOfThePuzzle.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -268,7 +249,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Sage of Ancient Lore", 211, Rarity.RARE, mage.cards.s.SageOfAncientLore.class)); cards.add(new SetCardInfo("Sanitarium Skeleton", 133, Rarity.COMMON, mage.cards.s.SanitariumSkeleton.class)); cards.add(new SetCardInfo("Scourge Wolf", 175, Rarity.UNCOMMON, mage.cards.s.ScourgeWolf.class)); - cards.add(new SetCardInfo("Scrounged Scythe", 252, Rarity.UNCOMMON, mage.cards.s.ScroungedScythe.class)); cards.add(new SetCardInfo("Seasons Past", 212, Rarity.MYTHIC, mage.cards.s.SeasonsPast.class)); cards.add(new SetCardInfo("Second Harvest", 213, Rarity.RARE, mage.cards.s.SecondHarvest.class)); cards.add(new SetCardInfo("Selfless Spirit", 42, Rarity.RARE, mage.cards.s.SelflessSpirit.class)); @@ -313,7 +293,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("Thornhide Wolves", 218, Rarity.COMMON, mage.cards.t.ThornhideWolves.class)); cards.add(new SetCardInfo("Thraben Foulbloods", 135, Rarity.COMMON, mage.cards.t.ThrabenFoulbloods.class)); cards.add(new SetCardInfo("Thraben Inspector", 51, Rarity.COMMON, mage.cards.t.ThrabenInspector.class)); - cards.add(new SetCardInfo("Timber Shredder", 201, Rarity.COMMON, mage.cards.t.TimberShredder.class)); cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class)); cards.add(new SetCardInfo("Topplegeist", 52, Rarity.UNCOMMON, mage.cards.t.Topplegeist.class)); cards.add(new SetCardInfo("Tormenting Voice", 181, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); @@ -324,21 +303,17 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet { cards.add(new SetCardInfo("True-Faith Censer", 262, Rarity.COMMON, mage.cards.t.TrueFaithCenser.class)); cards.add(new SetCardInfo("Ulrich of the Krallenhorde", 246, Rarity.RARE, mage.cards.u.UlrichOfTheKrallenhorde.class)); cards.add(new SetCardInfo("Ulrich's Kindred", 182, Rarity.UNCOMMON, mage.cards.u.UlrichsKindred.class)); - cards.add(new SetCardInfo("Ulrich, Uncontested Alpha", 246, Rarity.RARE, mage.cards.u.UlrichUncontestedAlpha.class)); - cards.add(new SetCardInfo("Ulvenwald Abomination", 221, Rarity.COMMON, mage.cards.u.UlvenwaldAbomination.class)); cards.add(new SetCardInfo("Ulvenwald Captive", 221, Rarity.COMMON, mage.cards.u.UlvenwaldCaptive.class)); cards.add(new SetCardInfo("Ulvenwald Hydra", 222, Rarity.RARE, mage.cards.u.UlvenwaldHydra.class)); cards.add(new SetCardInfo("Ulvenwald Mysteries", 223, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class)); cards.add(new SetCardInfo("Uncaged Fury", 183, Rarity.UNCOMMON, mage.cards.u.UncagedFury.class)); cards.add(new SetCardInfo("Vessel of Nascency", 224, Rarity.UNCOMMON, mage.cards.v.VesselOfNascency.class)); cards.add(new SetCardInfo("Veteran Cathar", 225, Rarity.UNCOMMON, mage.cards.v.VeteranCathar.class)); - cards.add(new SetCardInfo("Vildin-Pack Alpha", 159, Rarity.UNCOMMON, mage.cards.v.VildinPackAlpha.class)); cards.add(new SetCardInfo("Village Messenger", 184, Rarity.UNCOMMON, mage.cards.v.VillageMessenger.class)); cards.add(new SetCardInfo("Voldaren Pariah", 138, Rarity.RARE, mage.cards.v.VoldarenPariah.class)); cards.add(new SetCardInfo("Voracious Reader", 58, Rarity.UNCOMMON, mage.cards.v.VoraciousReader.class)); cards.add(new SetCardInfo("Weirded Vampire", 139, Rarity.COMMON, mage.cards.w.WeirdedVampire.class)); cards.add(new SetCardInfo("Weirding Wood", 226, Rarity.COMMON, mage.cards.w.WeirdingWood.class)); - cards.add(new SetCardInfo("Werewolf of Ancient Hunger", 211, Rarity.RARE, mage.cards.w.WerewolfOfAncientHunger.class)); cards.add(new SetCardInfo("Westvale Abbey", 275, Rarity.RARE, mage.cards.w.WestvaleAbbey.class)); cards.add(new SetCardInfo("Wharf Infiltrator", 96, Rarity.RARE, mage.cards.w.WharfInfiltrator.class)); cards.add(new SetCardInfo("Wild-Field Scarecrow", 263, Rarity.COMMON, mage.cards.w.WildFieldScarecrow.class)); diff --git a/Mage.Sets/src/mage/sets/SpotlightSeries.java b/Mage.Sets/src/mage/sets/SpotlightSeries.java index 92d42cff327..4abfa43a33c 100644 --- a/Mage.Sets/src/mage/sets/SpotlightSeries.java +++ b/Mage.Sets/src/mage/sets/SpotlightSeries.java @@ -22,9 +22,10 @@ public final class SpotlightSeries extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Cloud, Midgar Mercenary", 5, Rarity.MYTHIC, mage.cards.c.CloudMidgarMercenary.class)); - cards.add(new SetCardInfo("Get Lost", 6, Rarity.RARE, mage.cards.g.GetLost.class)); + cards.add(new SetCardInfo("Cloud, Midgar Mercenary", 4, Rarity.MYTHIC, mage.cards.c.CloudMidgarMercenary.class)); + cards.add(new SetCardInfo("Get Lost", 5, Rarity.RARE, mage.cards.g.GetLost.class)); cards.add(new SetCardInfo("Kaldra Compleat", 2, Rarity.MYTHIC, mage.cards.k.KaldraCompleat.class)); + cards.add(new SetCardInfo("Spectacular Spider-Man", 6, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class)); cards.add(new SetCardInfo("Sword of Forge and Frontier", 3, Rarity.MYTHIC, mage.cards.s.SwordOfForgeAndFrontier.class)); cards.add(new SetCardInfo("Terror of the Peaks", 1, Rarity.RARE, mage.cards.t.TerrorOfThePeaks.class)); } diff --git a/Mage.Sets/src/mage/sets/StarWars.java b/Mage.Sets/src/mage/sets/StarWars.java index b2f364c873b..fe63f0a5ab6 100644 --- a/Mage.Sets/src/mage/sets/StarWars.java +++ b/Mage.Sets/src/mage/sets/StarWars.java @@ -99,7 +99,6 @@ public final class StarWars extends ExpansionSet { cards.add(new SetCardInfo("Darth Maul", 178, Rarity.RARE, mage.cards.d.DarthMaul.class)); cards.add(new SetCardInfo("Darth Sidious, Sith Lord", 179, Rarity.MYTHIC, mage.cards.d.DarthSidiousSithLord.class)); cards.add(new SetCardInfo("Darth Tyranus, Count of Serenno", 180, Rarity.MYTHIC, mage.cards.d.DarthTyranusCountOfSerenno.class)); - cards.add(new SetCardInfo("Darth Vader", 140, Rarity.MYTHIC, mage.cards.d.DarthVader.class)); cards.add(new SetCardInfo("Death Trooper", 71, Rarity.UNCOMMON, mage.cards.d.DeathTrooper.class)); cards.add(new SetCardInfo("Delay Tactic", 504, Rarity.COMMON, mage.cards.d.DelayTactic.class)); cards.add(new SetCardInfo("Deploy The Troops", 8, Rarity.UNCOMMON, mage.cards.d.DeployTheTroops.class)); diff --git a/Mage.Sets/src/mage/sets/StoreChampionships.java b/Mage.Sets/src/mage/sets/StoreChampionships.java index b9a6e890afe..ea3ef14a33e 100644 --- a/Mage.Sets/src/mage/sets/StoreChampionships.java +++ b/Mage.Sets/src/mage/sets/StoreChampionships.java @@ -55,7 +55,6 @@ public final class StoreChampionships extends ExpansionSet { cards.add(new SetCardInfo("Preacher of the Schism", 34, Rarity.RARE, mage.cards.p.PreacherOfTheSchism.class)); cards.add(new SetCardInfo("Preordain", 39, Rarity.RARE, mage.cards.p.Preordain.class)); cards.add(new SetCardInfo("Reality Smasher", 31, Rarity.RARE, mage.cards.r.RealitySmasher.class)); - cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 44, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class)); cards.add(new SetCardInfo("Shark Typhoon", 28, Rarity.RARE, mage.cards.s.SharkTyphoon.class)); cards.add(new SetCardInfo("Slickshot Show-Off", 43, Rarity.RARE, mage.cards.s.SlickshotShowOff.class)); cards.add(new SetCardInfo("Spell Pierce", 4, Rarity.RARE, mage.cards.s.SpellPierce.class)); diff --git a/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtles.java b/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtles.java new file mode 100644 index 00000000000..c103cf0d5e0 --- /dev/null +++ b/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtles.java @@ -0,0 +1,40 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class TeenageMutantNinjaTurtles extends ExpansionSet { + + private static final TeenageMutantNinjaTurtles instance = new TeenageMutantNinjaTurtles(); + + public static TeenageMutantNinjaTurtles getInstance() { + return instance; + } + + private TeenageMutantNinjaTurtles() { + super("Teenage Mutant Ninja Turtles", "TMT", ExpansionSet.buildDate(2026, 3, 6), SetType.EXPANSION); + this.blockName = "Teenage Mutant Ninja Turtles"; // for sorting in GUI + this.hasBasicLands = true; + + cards.add(new SetCardInfo("April O'Neil, Hacktivist", 29, Rarity.RARE, mage.cards.a.AprilONeilHacktivist.class)); + cards.add(new SetCardInfo("Bebop & Rocksteady", 140, Rarity.RARE, mage.cards.b.BebopAndRocksteady.class)); + cards.add(new SetCardInfo("Casey Jones, Jury-Rig Justiciar", 87, Rarity.UNCOMMON, mage.cards.c.CaseyJonesJuryRigJusticiar.class)); + cards.add(new SetCardInfo("Forest", 257, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 314, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 311, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Krang, Master Mind", 43, Rarity.RARE, mage.cards.k.KrangMasterMind.class)); + cards.add(new SetCardInfo("Mountain", 256, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 313, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 253, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 310, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Raphael's Technique", 105, Rarity.RARE, mage.cards.r.RaphaelsTechnique.class)); + cards.add(new SetCardInfo("Super Shredder", 83, Rarity.MYTHIC, mage.cards.s.SuperShredder.class)); + cards.add(new SetCardInfo("Swamp", 255, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 312, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + } +} diff --git a/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtlesEternal.java b/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtlesEternal.java new file mode 100644 index 00000000000..7a0a2eebf07 --- /dev/null +++ b/Mage.Sets/src/mage/sets/TeenageMutantNinjaTurtlesEternal.java @@ -0,0 +1,33 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class TeenageMutantNinjaTurtlesEternal extends ExpansionSet { + + private static final TeenageMutantNinjaTurtlesEternal instance = new TeenageMutantNinjaTurtlesEternal(); + + public static TeenageMutantNinjaTurtlesEternal getInstance() { + return instance; + } + + private TeenageMutantNinjaTurtlesEternal() { + super("Teenage Mutant Ninja Turtles Eternal", "TMC", ExpansionSet.buildDate(2026, 3, 6), SetType.EXPANSION); + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Dark Ritual", 131, Rarity.MYTHIC, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Donatello, Rad Scientist", 109, Rarity.MYTHIC, mage.cards.d.DonatelloRadScientist.class)); + cards.add(new SetCardInfo("Donatello, the Brains", 2, Rarity.MYTHIC, mage.cards.d.DonatelloTheBrains.class)); + cards.add(new SetCardInfo("Donnie & April, Adorkable Duo", 111, Rarity.RARE, mage.cards.d.DonnieAndAprilAdorkableDuo.class)); + cards.add(new SetCardInfo("Heroes in a Half Shell", 6, Rarity.MYTHIC, mage.cards.h.HeroesInAHalfShell.class)); + cards.add(new SetCardInfo("Leonardo, Worldly Warrior", 101, Rarity.MYTHIC, mage.cards.l.LeonardoWorldlyWarrior.class)); + cards.add(new SetCardInfo("Leonardo, the Balance", 1, Rarity.MYTHIC, mage.cards.l.LeonardoTheBalance.class)); + cards.add(new SetCardInfo("Michelangelo, the Heart", 5, Rarity.MYTHIC, mage.cards.m.MichelangeloTheHeart.class)); + cards.add(new SetCardInfo("Raphael, the Muscle", 4, Rarity.MYTHIC, mage.cards.r.RaphaelTheMuscle.class)); + cards.add(new SetCardInfo("Splinter, the Mentor", 3, Rarity.MYTHIC, mage.cards.s.SplinterTheMentor.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java index b69a7f099d0..19c32dd560e 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalan.java @@ -1,15 +1,12 @@ package mage.sets; -import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.cards.repository.CardInfo; -import mage.constants.Rarity; -import mage.constants.SetType; -import mage.util.RandomUtil; 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; @@ -65,8 +62,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Another Chance", 90, Rarity.COMMON, mage.cards.a.AnotherChance.class)); cards.add(new SetCardInfo("Armored Kincaller", 174, Rarity.COMMON, mage.cards.a.ArmoredKincaller.class)); cards.add(new SetCardInfo("Attentive Sunscribe", 4, Rarity.COMMON, mage.cards.a.AttentiveSunscribe.class)); - cards.add(new SetCardInfo("Barracks of the Thousand", 357, Rarity.RARE, mage.cards.b.BarracksOfTheThousand.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Barracks of the Thousand", 39, Rarity.RARE, mage.cards.b.BarracksOfTheThousand.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bartolome del Presidio", 224, Rarity.UNCOMMON, mage.cards.b.BartolomeDelPresidio.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bartolome del Presidio", 301, Rarity.UNCOMMON, mage.cards.b.BartolomeDelPresidio.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bartolome del Presidio", 409, Rarity.UNCOMMON, mage.cards.b.BartolomeDelPresidio.class, NON_FULL_USE_VARIOUS)); @@ -77,7 +72,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Belligerent Yearling", 133, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Belligerent Yearling", 320, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bitter Triumph", 91, Rarity.UNCOMMON, mage.cards.b.BitterTriumph.class)); - cards.add(new SetCardInfo("Bladewheel Chariot", 36, Rarity.UNCOMMON, mage.cards.b.BladewheelChariot.class)); cards.add(new SetCardInfo("Bloodletter of Aclazotz", 336, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodletter of Aclazotz", 92, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodthorn Flail", 93, Rarity.UNCOMMON, mage.cards.b.BloodthornFlail.class)); @@ -86,8 +80,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Brackish Blunder", 46, Rarity.COMMON, mage.cards.b.BrackishBlunder.class)); cards.add(new SetCardInfo("Braided Net", 360, Rarity.RARE, mage.cards.b.BraidedNet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Braided Net", 47, Rarity.RARE, mage.cards.b.BraidedNet.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braided Quipu", 360, Rarity.RARE, mage.cards.b.BraidedQuipu.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Braided Quipu", 47, Rarity.RARE, mage.cards.b.BraidedQuipu.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brass's Tunnel-Grinder", 135, Rarity.RARE, mage.cards.b.BrasssTunnelGrinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brass's Tunnel-Grinder", 373, Rarity.RARE, mage.cards.b.BrasssTunnelGrinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Brazen Blademaster", 136, Rarity.COMMON, mage.cards.b.BrazenBlademaster.class)); @@ -129,14 +121,12 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Colossadactyl", 180, Rarity.UNCOMMON, mage.cards.c.Colossadactyl.class)); cards.add(new SetCardInfo("Compass Gnome", 250, Rarity.COMMON, mage.cards.c.CompassGnome.class)); cards.add(new SetCardInfo("Confounding Riddle", 50, Rarity.UNCOMMON, mage.cards.c.ConfoundingRiddle.class)); - cards.add(new SetCardInfo("Consuming Sepulcher", 128, Rarity.COMMON, mage.cards.c.ConsumingSepulcher.class)); cards.add(new SetCardInfo("Contested Game Ball", 251, Rarity.UNCOMMON, mage.cards.c.ContestedGameBall.class)); cards.add(new SetCardInfo("Corpses of the Lost", 366, Rarity.RARE, mage.cards.c.CorpsesOfTheLost.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Corpses of the Lost", 98, Rarity.RARE, mage.cards.c.CorpsesOfTheLost.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cosmium Blast", 7, Rarity.COMMON, mage.cards.c.CosmiumBlast.class)); cards.add(new SetCardInfo("Cosmium Confluence", 181, Rarity.RARE, mage.cards.c.CosmiumConfluence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Cosmium Confluence", 379, Rarity.RARE, mage.cards.c.CosmiumConfluence.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Cosmium Kiln", 6, Rarity.UNCOMMON, mage.cards.c.CosmiumKiln.class)); cards.add(new SetCardInfo("Council of Echoes", 51, Rarity.UNCOMMON, mage.cards.c.CouncilOfEchoes.class)); cards.add(new SetCardInfo("Curator of Sun's Creation", 141, Rarity.UNCOMMON, mage.cards.c.CuratorOfSunsCreation.class)); cards.add(new SetCardInfo("Daring Discovery", 142, Rarity.COMMON, mage.cards.d.DaringDiscovery.class)); @@ -156,14 +146,11 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Didact Echo", 53, Rarity.COMMON, mage.cards.d.DidactEcho.class)); cards.add(new SetCardInfo("Digsite Conservator", 252, Rarity.UNCOMMON, mage.cards.d.DigsiteConservator.class)); cards.add(new SetCardInfo("Dinotomaton", 144, Rarity.COMMON, mage.cards.d.Dinotomaton.class)); - cards.add(new SetCardInfo("Dire Blunderbuss", 145, Rarity.RARE, mage.cards.d.DireBlunderbuss.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Dire Blunderbuss", 374, Rarity.RARE, mage.cards.d.DireBlunderbuss.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire Flail", 145, Rarity.RARE, mage.cards.d.DireFlail.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dire Flail", 374, Rarity.RARE, mage.cards.d.DireFlail.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Disruptor Wanderglyph", 253, Rarity.COMMON, mage.cards.d.DisruptorWanderglyph.class)); cards.add(new SetCardInfo("Disturbed Slumber", 182, Rarity.COMMON, mage.cards.d.DisturbedSlumber.class)); cards.add(new SetCardInfo("Dowsing Device", 146, Rarity.UNCOMMON, mage.cards.d.DowsingDevice.class)); - cards.add(new SetCardInfo("Dread Osseosaur", 129, Rarity.UNCOMMON, mage.cards.d.DreadOsseosaur.class)); cards.add(new SetCardInfo("Dreadmaw's Ire", 147, Rarity.UNCOMMON, mage.cards.d.DreadmawsIre.class)); cards.add(new SetCardInfo("Dusk Rose Reliquary", 10, Rarity.UNCOMMON, mage.cards.d.DuskRoseReliquary.class)); cards.add(new SetCardInfo("Earthshaker Dreadmaw", 183, Rarity.UNCOMMON, mage.cards.e.EarthshakerDreadmaw.class, NON_FULL_USE_VARIOUS)); @@ -187,7 +174,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Frilled Cave-Wurm", 57, Rarity.COMMON, mage.cards.f.FrilledCaveWurm.class)); cards.add(new SetCardInfo("Fungal Fortitude", 106, Rarity.COMMON, mage.cards.f.FungalFortitude.class)); cards.add(new SetCardInfo("Gargantuan Leech", 107, Rarity.UNCOMMON, mage.cards.g.GargantuanLeech.class)); - cards.add(new SetCardInfo("Geode Grotto", 146, Rarity.UNCOMMON, mage.cards.g.GeodeGrotto.class)); cards.add(new SetCardInfo("Geological Appraiser", 150, Rarity.UNCOMMON, mage.cards.g.GeologicalAppraiser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Geological Appraiser", 407, Rarity.UNCOMMON, mage.cards.g.GeologicalAppraiser.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Get Lost", 14, Rarity.RARE, mage.cards.g.GetLost.class, NON_FULL_USE_VARIOUS)); @@ -206,7 +192,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Growing Rites of Itlimoc", 188, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Growing Rites of Itlimoc", 380, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Guardian of the Great Door", 16, Rarity.UNCOMMON, mage.cards.g.GuardianOfTheGreatDoor.class)); - cards.add(new SetCardInfo("Guidestone Compass", 62, Rarity.UNCOMMON, mage.cards.g.GuidestoneCompass.class)); cards.add(new SetCardInfo("Helping Hand", 17, Rarity.UNCOMMON, mage.cards.h.HelpingHand.class)); cards.add(new SetCardInfo("Hermitic Nautilus", 58, Rarity.UNCOMMON, mage.cards.h.HermiticNautilus.class)); cards.add(new SetCardInfo("Hidden Cataract", 273, Rarity.COMMON, mage.cards.h.HiddenCataract.class)); @@ -227,7 +212,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Hulking Raptor", 327, Rarity.RARE, mage.cards.h.HulkingRaptor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hunter's Blowgun", 255, Rarity.COMMON, mage.cards.h.HuntersBlowgun.class)); cards.add(new SetCardInfo("Hurl into History", 59, Rarity.UNCOMMON, mage.cards.h.HurlIntoHistory.class)); - cards.add(new SetCardInfo("Iceberg Titan", 60, Rarity.COMMON, mage.cards.i.IcebergTitan.class)); cards.add(new SetCardInfo("Idol of the Deep King", 155, Rarity.COMMON, mage.cards.i.IdolOfTheDeepKing.class)); cards.add(new SetCardInfo("In the Presence of Ages", 192, Rarity.COMMON, mage.cards.i.InThePresenceOfAges.class)); cards.add(new SetCardInfo("Inti, Seneschal of the Sun", 156, Rarity.RARE, mage.cards.i.IntiSeneschalOfTheSun.class, NON_FULL_USE_VARIOUS)); @@ -239,19 +223,15 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_UST_VARIOUS)); cards.add(new SetCardInfo("Island", 395, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 396, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 188, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 380, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Itzquinth, Firstborn of Gishath", 230, Rarity.UNCOMMON, mage.cards.i.ItzquinthFirstbornOfGishath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Itzquinth, Firstborn of Gishath", 331, Rarity.UNCOMMON, mage.cards.i.ItzquinthFirstbornOfGishath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ixalli's Lorekeeper", 194, Rarity.UNCOMMON, mage.cards.i.IxallisLorekeeper.class)); cards.add(new SetCardInfo("Jade Seedstones", 195, Rarity.UNCOMMON, mage.cards.j.JadeSeedstones.class)); - cards.add(new SetCardInfo("Jadeheart Attendant", 195, Rarity.UNCOMMON, mage.cards.j.JadeheartAttendant.class)); cards.add(new SetCardInfo("Jadelight Spelunker", 196, Rarity.RARE, mage.cards.j.JadelightSpelunker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jadelight Spelunker", 382, Rarity.RARE, mage.cards.j.JadelightSpelunker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jadelight Spelunker", 403, Rarity.RARE, mage.cards.j.JadelightSpelunker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Join the Dead", 110, Rarity.COMMON, mage.cards.j.JoinTheDead.class)); cards.add(new SetCardInfo("Kaslem's Stonetree", 197, Rarity.COMMON, mage.cards.k.KaslemsStonetree.class)); - cards.add(new SetCardInfo("Kaslem's Strider", 197, Rarity.COMMON, mage.cards.k.KaslemsStrider.class)); cards.add(new SetCardInfo("Kellan, Daring Traveler", 231, Rarity.RARE, mage.cards.k.KellanDaringTraveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kellan, Daring Traveler", 341, Rarity.RARE, mage.cards.k.KellanDaringTraveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kinjalli's Dawnrunner", 19, Rarity.UNCOMMON, mage.cards.k.KinjallisDawnrunner.class)); @@ -261,8 +241,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Kutzil's Flanker", 355, Rarity.RARE, mage.cards.k.KutzilsFlanker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kutzil, Malamet Exemplar", 232, Rarity.UNCOMMON, mage.cards.k.KutzilMalametExemplar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kutzil, Malamet Exemplar", 304, Rarity.UNCOMMON, mage.cards.k.KutzilMalametExemplar.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Locus of Enlightenment", 362, Rarity.MYTHIC, mage.cards.l.LocusOfEnlightenment.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Locus of Enlightenment", 55, Rarity.MYTHIC, mage.cards.l.LocusOfEnlightenment.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lodestone Needle", 62, Rarity.UNCOMMON, mage.cards.l.LodestoneNeedle.class)); cards.add(new SetCardInfo("Magmatic Galleon", 157, Rarity.RARE, mage.cards.m.MagmaticGalleon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Magmatic Galleon", 376, Rarity.RARE, mage.cards.m.MagmaticGalleon.class, NON_FULL_USE_VARIOUS)); @@ -277,8 +255,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Marauding Brinefang", 64, Rarity.COMMON, mage.cards.m.MaraudingBrinefang.class)); cards.add(new SetCardInfo("Market Gnome", 22, Rarity.UNCOMMON, mage.cards.m.MarketGnome.class)); cards.add(new SetCardInfo("Master's Guide-Mural", 233, Rarity.UNCOMMON, mage.cards.m.MastersGuideMural.class)); - cards.add(new SetCardInfo("Master's Manufactory", 233, Rarity.UNCOMMON, mage.cards.m.MastersManufactory.class)); - cards.add(new SetCardInfo("Mastercraft Raptor", 164, Rarity.UNCOMMON, mage.cards.m.MastercraftRaptor.class)); cards.add(new SetCardInfo("Matzalantli, the Great Door", 256, Rarity.RARE, mage.cards.m.MatzalantliTheGreatDoor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Matzalantli, the Great Door", 387, Rarity.RARE, mage.cards.m.MatzalantliTheGreatDoor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mephitic Draught", 112, Rarity.COMMON, mage.cards.m.MephiticDraught.class)); @@ -292,7 +268,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_UST_VARIOUS)); cards.add(new SetCardInfo("Mountain", 399, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 400, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mycoid Maze", 217, Rarity.UNCOMMON, mage.cards.m.MycoidMaze.class)); cards.add(new SetCardInfo("Nicanzil, Current Conductor", 236, Rarity.UNCOMMON, mage.cards.n.NicanzilCurrentConductor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nicanzil, Current Conductor", 306, Rarity.UNCOMMON, mage.cards.n.NicanzilCurrentConductor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nurturing Bristleback", 203, Rarity.COMMON, mage.cards.n.NurturingBristleback.class)); @@ -309,7 +284,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Oltec Cloud Guard", 28, Rarity.COMMON, mage.cards.o.OltecCloudGuard.class)); cards.add(new SetCardInfo("Orazca Puzzle-Door", 68, Rarity.COMMON, mage.cards.o.OrazcaPuzzleDoor.class)); cards.add(new SetCardInfo("Oteclan Landmark", 29, Rarity.COMMON, mage.cards.o.OteclanLandmark.class)); - cards.add(new SetCardInfo("Oteclan Levitator", 29, Rarity.COMMON, mage.cards.o.OteclanLevitator.class)); cards.add(new SetCardInfo("Out of Air", 69, Rarity.COMMON, mage.cards.o.OutOfAir.class)); cards.add(new SetCardInfo("Over the Edge", 205, Rarity.COMMON, mage.cards.o.OverTheEdge.class)); cards.add(new SetCardInfo("Palani's Hatcher", 237, Rarity.RARE, mage.cards.p.PalanisHatcher.class, NON_FULL_USE_VARIOUS)); @@ -359,9 +333,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("River Herald Scout", 72, Rarity.COMMON, mage.cards.r.RiverHeraldScout.class)); cards.add(new SetCardInfo("Roaming Throne", 258, Rarity.RARE, mage.cards.r.RoamingThrone.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Roaming Throne", 344, Rarity.RARE, mage.cards.r.RoamingThrone.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roar of the Fifth People", 189, Rarity.MYTHIC, mage.cards.r.RoarOfTheFifthPeople.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roar of the Fifth People", 296, Rarity.MYTHIC, mage.cards.r.RoarOfTheFifthPeople.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Roar of the Fifth People", 339, Rarity.MYTHIC, mage.cards.r.RoarOfTheFifthPeople.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ruin-Lurker Bat", 33, Rarity.UNCOMMON, mage.cards.r.RuinLurkerBat.class)); cards.add(new SetCardInfo("Rumbling Rockslide", 163, Rarity.COMMON, mage.cards.r.RumblingRockslide.class)); cards.add(new SetCardInfo("Runaway Boulder", 259, Rarity.COMMON, mage.cards.r.RunawayBoulder.class)); @@ -369,8 +340,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Saheeli's Lattice", 164, Rarity.UNCOMMON, mage.cards.s.SaheelisLattice.class)); cards.add(new SetCardInfo("Saheeli, the Sun's Brilliance", 239, Rarity.MYTHIC, mage.cards.s.SaheeliTheSunsBrilliance.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Saheeli, the Sun's Brilliance", 308, Rarity.MYTHIC, mage.cards.s.SaheeliTheSunsBrilliance.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sandswirl Wanderglyph", 358, Rarity.RARE, mage.cards.s.SandswirlWanderglyph.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sandswirl Wanderglyph", 41, Rarity.RARE, mage.cards.s.SandswirlWanderglyph.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sanguine Evangelist", 34, Rarity.RARE, mage.cards.s.SanguineEvangelist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sanguine Evangelist", 356, Rarity.RARE, mage.cards.s.SanguineEvangelist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scampering Surveyor", 260, Rarity.UNCOMMON, mage.cards.s.ScamperingSurveyor.class)); @@ -382,7 +351,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Self-Reflection", 74, Rarity.UNCOMMON, mage.cards.s.SelfReflection.class)); cards.add(new SetCardInfo("Sentinel of the Nameless City", 211, Rarity.RARE, mage.cards.s.SentinelOfTheNamelessCity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sentinel of the Nameless City", 383, Rarity.RARE, mage.cards.s.SentinelOfTheNamelessCity.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Shadows' Lair", 108, Rarity.UNCOMMON, mage.cards.s.ShadowsLair.class)); cards.add(new SetCardInfo("Shipwreck Sentry", 75, Rarity.COMMON, mage.cards.s.ShipwreckSentry.class)); cards.add(new SetCardInfo("Sinuous Benthisaur", 76, Rarity.UNCOMMON, mage.cards.s.SinuousBenthisaur.class)); cards.add(new SetCardInfo("Skullcap Snail", 119, Rarity.COMMON, mage.cards.s.SkullcapSnail.class)); @@ -394,7 +362,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Souls of the Lost", 369, Rarity.RARE, mage.cards.s.SoulsOfTheLost.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sovereign Okinec Ahau", 240, Rarity.MYTHIC, mage.cards.s.SovereignOkinecAhau.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sovereign Okinec Ahau", 309, Rarity.MYTHIC, mage.cards.s.SovereignOkinecAhau.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sovereign's Macuahuitl", 155, Rarity.COMMON, mage.cards.s.SovereignsMacuahuitl.class)); cards.add(new SetCardInfo("Spelunking", 213, Rarity.UNCOMMON, mage.cards.s.Spelunking.class)); cards.add(new SetCardInfo("Spring-Loaded Sawblades", 36, Rarity.UNCOMMON, mage.cards.s.SpringLoadedSawblades.class)); cards.add(new SetCardInfo("Spyglass Siren", 405, Rarity.UNCOMMON, mage.cards.s.SpyglassSiren.class, NON_FULL_USE_VARIOUS)); @@ -410,7 +377,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Stinging Cave Crawler", 124, Rarity.UNCOMMON, mage.cards.s.StingingCaveCrawler.class)); cards.add(new SetCardInfo("Subterranean Schooner", 365, Rarity.RARE, mage.cards.s.SubterraneanSchooner.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Subterranean Schooner", 80, Rarity.RARE, mage.cards.s.SubterraneanSchooner.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sunbird Effigy", 262, Rarity.UNCOMMON, mage.cards.s.SunbirdEffigy.class)); cards.add(new SetCardInfo("Sunbird Standard", 262, Rarity.UNCOMMON, mage.cards.s.SunbirdStandard.class)); cards.add(new SetCardInfo("Sunfire Torch", 167, Rarity.COMMON, mage.cards.s.SunfireTorch.class)); cards.add(new SetCardInfo("Sunken Citadel", 285, Rarity.RARE, mage.cards.s.SunkenCitadel.class, NON_FULL_USE_VARIOUS)); @@ -426,18 +392,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Tarrian's Soulcleaver", 264, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tarrian's Soulcleaver", 389, Rarity.RARE, mage.cards.t.TarriansSoulcleaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tectonic Hazard", 169, Rarity.COMMON, mage.cards.t.TectonicHazard.class)); - cards.add(new SetCardInfo("Tecutlan, the Searing Rift", 135, Rarity.RARE, mage.cards.t.TecutlanTheSearingRift.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tecutlan, the Searing Rift", 373, Rarity.RARE, mage.cards.t.TecutlanTheSearingRift.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Civilization", 26, Rarity.MYTHIC, mage.cards.t.TempleOfCivilization.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Civilization", 314, Rarity.MYTHIC, mage.cards.t.TempleOfCivilization.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Cultivation", 204, Rarity.MYTHIC, mage.cards.t.TempleOfCultivation.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Cultivation", 318, Rarity.MYTHIC, mage.cards.t.TempleOfCultivation.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Cyclical Time", 315, Rarity.MYTHIC, mage.cards.t.TempleOfCyclicalTime.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Cyclical Time", 67, Rarity.MYTHIC, mage.cards.t.TempleOfCyclicalTime.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Power", 158, Rarity.MYTHIC, mage.cards.t.TempleOfPower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of Power", 317, Rarity.MYTHIC, mage.cards.t.TempleOfPower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of the Dead", 316, Rarity.MYTHIC, mage.cards.t.TempleOfTheDead.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Temple of the Dead", 88, Rarity.MYTHIC, mage.cards.t.TempleOfTheDead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tendril of the Mycotyrant", 215, Rarity.UNCOMMON, mage.cards.t.TendrilOfTheMycotyrant.class)); cards.add(new SetCardInfo("Terror Tide", 127, Rarity.RARE, mage.cards.t.TerrorTide.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Terror Tide", 372, Rarity.RARE, mage.cards.t.TerrorTide.class, NON_FULL_USE_VARIOUS)); @@ -445,24 +399,16 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("The Ancient One", 319, Rarity.MYTHIC, mage.cards.t.TheAncientOne.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Belligerent", 225, Rarity.RARE, mage.cards.t.TheBelligerent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Belligerent", 384, Rarity.RARE, mage.cards.t.TheBelligerent.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Core", 256, Rarity.RARE, mage.cards.t.TheCore.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Core", 387, Rarity.RARE, mage.cards.t.TheCore.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Enigma Jewel", 362, Rarity.MYTHIC, mage.cards.t.TheEnigmaJewel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Enigma Jewel", 55, Rarity.MYTHIC, mage.cards.t.TheEnigmaJewel.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Everflowing Well", 363, Rarity.RARE, mage.cards.t.TheEverflowingWell.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Everflowing Well", 56, Rarity.RARE, mage.cards.t.TheEverflowingWell.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Grim Captain", 266, Rarity.RARE, mage.cards.t.TheGrimCaptain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Grim Captain", 313, Rarity.RARE, mage.cards.t.TheGrimCaptain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Millennium Calendar", 257, Rarity.MYTHIC, mage.cards.t.TheMillenniumCalendar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Millennium Calendar", 388, Rarity.MYTHIC, mage.cards.t.TheMillenniumCalendar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Mycotyrant", 235, Rarity.MYTHIC, mage.cards.t.TheMycotyrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Mycotyrant", 305, Rarity.MYTHIC, mage.cards.t.TheMycotyrant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Myriad Pools", 363, Rarity.RARE, mage.cards.t.TheMyriadPools.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Myriad Pools", 56, Rarity.RARE, mage.cards.t.TheMyriadPools.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Skullspore Nexus", 212, Rarity.MYTHIC, mage.cards.t.TheSkullsporeNexus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Skullspore Nexus", 340, Rarity.MYTHIC, mage.cards.t.TheSkullsporeNexus.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Tomb of Aclazotz", 126, Rarity.RARE, mage.cards.t.TheTombOfAclazotz.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Tomb of Aclazotz", 371, Rarity.RARE, mage.cards.t.TheTombOfAclazotz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thousand Moons Crackshot", 37, Rarity.COMMON, mage.cards.t.ThousandMoonsCrackshot.class)); cards.add(new SetCardInfo("Thousand Moons Infantry", 38, Rarity.COMMON, mage.cards.t.ThousandMoonsInfantry.class)); cards.add(new SetCardInfo("Thousand Moons Smithy", 357, Rarity.RARE, mage.cards.t.ThousandMoonsSmithy.class, NON_FULL_USE_VARIOUS)); @@ -477,8 +423,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Tishana's Tidebinder", 335, Rarity.RARE, mage.cards.t.TishanasTidebinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tishana's Tidebinder", 81, Rarity.RARE, mage.cards.t.TishanasTidebinder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tithing Blade", 128, Rarity.COMMON, mage.cards.t.TithingBlade.class)); - cards.add(new SetCardInfo("Treasure Cove", 267, Rarity.RARE, mage.cards.t.TreasureCove.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Treasure Cove", 391, Rarity.RARE, mage.cards.t.TreasureCove.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Treasure Map", 267, Rarity.RARE, mage.cards.t.TreasureMap.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Treasure Map", 391, Rarity.RARE, mage.cards.t.TreasureMap.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Triumphant Chomp", 170, Rarity.UNCOMMON, mage.cards.t.TriumphantChomp.class)); @@ -503,7 +447,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet { cards.add(new SetCardInfo("Warden of the Inner Sky", 359, Rarity.RARE, mage.cards.w.WardenOfTheInnerSky.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warden of the Inner Sky", 43, Rarity.RARE, mage.cards.w.WardenOfTheInnerSky.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Waterlogged Hulk", 83, Rarity.UNCOMMON, mage.cards.w.WaterloggedHulk.class)); - cards.add(new SetCardInfo("Watertight Gondola", 83, Rarity.UNCOMMON, mage.cards.w.WatertightGondola.class)); cards.add(new SetCardInfo("Waterwind Scout", 84, Rarity.COMMON, mage.cards.w.WaterwindScout.class)); cards.add(new SetCardInfo("Waylaying Pirates", 85, Rarity.COMMON, mage.cards.w.WaylayingPirates.class)); cards.add(new SetCardInfo("Zoetic Glyph", 86, Rarity.UNCOMMON, mage.cards.z.ZoeticGlyph.class)); @@ -578,15 +521,15 @@ class TheLostCavernsOfIxalanCollator implements BoosterCollator { // 1.3875 B uncommons (111 / 80) // 1.3875 C uncommons (111 / 80) private final RarityConfiguration uncommonRuns = new RarityConfiguration( - BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, - BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, - BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, - BCC, - BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, - BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, - BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, + BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, + BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, + BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, BCC, + BCC, + BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, + BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, + BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, BBC, - ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, + ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC, ABC ); diff --git a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java index 0a1ca2edf90..1fccd3b5ec5 100644 --- a/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java +++ b/Mage.Sets/src/mage/sets/TheLostCavernsOfIxalanCommander.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -31,7 +30,6 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Amulet of Vigor", 103, Rarity.RARE, mage.cards.a.AmuletOfVigor.class)); cards.add(new SetCardInfo("Angrath's Marauders", 215, Rarity.RARE, mage.cards.a.AngrathsMarauders.class)); cards.add(new SetCardInfo("Apex Altisaur", 232, Rarity.RARE, mage.cards.a.ApexAltisaur.class)); - cards.add(new SetCardInfo("Apex Observatory", 15, Rarity.MYTHIC, mage.cards.a.ApexObservatory.class)); cards.add(new SetCardInfo("Arcane Signet", 104, Rarity.UNCOMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Arch of Orazca", 319, Rarity.RARE, mage.cards.a.ArchOfOrazca.class)); cards.add(new SetCardInfo("Archaeomancer's Map", 101, Rarity.RARE, mage.cards.a.ArchaeomancersMap.class)); @@ -85,7 +83,6 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Coralhelm Commander", 148, Rarity.RARE, mage.cards.c.CoralhelmCommander.class)); cards.add(new SetCardInfo("Cordial Vampire", 189, Rarity.RARE, mage.cards.c.CordialVampire.class)); cards.add(new SetCardInfo("Corsair Captain", 149, Rarity.RARE, mage.cards.c.CorsairCaptain.class)); - cards.add(new SetCardInfo("Cosmium Catalyst", 11, Rarity.RARE, mage.cards.c.CosmiumCatalyst.class)); cards.add(new SetCardInfo("Crossway Troublemakers", 190, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class)); cards.add(new SetCardInfo("Cruel Celebrant", 267, Rarity.UNCOMMON, mage.cards.c.CruelCelebrant.class)); cards.add(new SetCardInfo("Crumbling Necropolis", 326, Rarity.UNCOMMON, mage.cards.c.CrumblingNecropolis.class)); @@ -285,10 +282,8 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Terramorphic Expanse", 360, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Tetzin, Gnome Champion", 13, Rarity.RARE, mage.cards.t.TetzinGnomeChampion.class)); cards.add(new SetCardInfo("Thassa, God of the Sea", 176, Rarity.MYTHIC, mage.cards.t.ThassaGodOfTheSea.class)); - cards.add(new SetCardInfo("The Golden-Gear Colossus", 13, Rarity.RARE, mage.cards.t.TheGoldenGearColossus.class)); cards.add(new SetCardInfo("The Indomitable", 43, Rarity.RARE, mage.cards.t.TheIndomitable.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Indomitable", 75, Rarity.RARE, mage.cards.t.TheIndomitable.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("The Grim Captain's Locker", 82, Rarity.RARE, mage.cards.t.TheGrimCaptainsLocker.class)); cards.add(new SetCardInfo("Thieving Skydiver", 177, Rarity.RARE, mage.cards.t.ThievingSkydiver.class)); cards.add(new SetCardInfo("Thought Vessel", 118, Rarity.UNCOMMON, mage.cards.t.ThoughtVessel.class)); cards.add(new SetCardInfo("Thriving Bluff", 361, Rarity.COMMON, mage.cards.t.ThrivingBluff.class)); @@ -329,7 +324,6 @@ public final class TheLostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Windfall", 180, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); cards.add(new SetCardInfo("Worn Powerstone", 120, Rarity.UNCOMMON, mage.cards.w.WornPowerstone.class)); cards.add(new SetCardInfo("Wrathful Raptors", 88, Rarity.RARE, mage.cards.w.WrathfulRaptors.class)); - cards.add(new SetCardInfo("Wretched Bonemass", 10, Rarity.RARE, mage.cards.w.WretchedBonemass.class)); cards.add(new SetCardInfo("Xavier Sal, Infested Captain", 14, Rarity.RARE, mage.cards.x.XavierSalInfestedCaptain.class)); cards.add(new SetCardInfo("Xenagos, God of Revels", 295, Rarity.MYTHIC, mage.cards.x.XenagosGodOfRevels.class)); cards.add(new SetCardInfo("Xolatoyac, the Smiling Flood", 8, Rarity.MYTHIC, mage.cards.x.XolatoyacTheSmilingFlood.class)); diff --git a/Mage.Sets/src/mage/sets/Transformers.java b/Mage.Sets/src/mage/sets/Transformers.java index 0e8daddb516..ae99a1418d0 100644 --- a/Mage.Sets/src/mage/sets/Transformers.java +++ b/Mage.Sets/src/mage/sets/Transformers.java @@ -19,31 +19,18 @@ public final class Transformers extends ExpansionSet { super("Transformers", "BOT", ExpansionSet.buildDate(2022, 11, 18), SetType.SUPPLEMENTAL); this.hasBasicLands = false; - cards.add(new SetCardInfo("Arcee, Acrobatic Coupe", 7, Rarity.MYTHIC, mage.cards.a.ArceeAcrobaticCoupe.class)); cards.add(new SetCardInfo("Arcee, Sharpshooter", 7, Rarity.MYTHIC, mage.cards.a.ArceeSharpshooter.class)); - cards.add(new SetCardInfo("Blitzwing, Adaptive Assailant", 4, Rarity.MYTHIC, mage.cards.b.BlitzwingAdaptiveAssailant.class)); cards.add(new SetCardInfo("Blitzwing, Cruel Tormentor", 4, Rarity.MYTHIC, mage.cards.b.BlitzwingCruelTormentor.class)); - cards.add(new SetCardInfo("Cyclonus, Cybertronian Fighter", 9, Rarity.MYTHIC, mage.cards.c.CyclonusCybertronianFighter.class)); cards.add(new SetCardInfo("Cyclonus, the Saboteur", 9, Rarity.MYTHIC, mage.cards.c.CyclonusTheSaboteur.class)); cards.add(new SetCardInfo("Flamewar, Brash Veteran", 10, Rarity.MYTHIC, mage.cards.f.FlamewarBrashVeteran.class)); - cards.add(new SetCardInfo("Flamewar, Streetwise Operative", 10, Rarity.MYTHIC, mage.cards.f.FlamewarStreetwiseOperative.class)); cards.add(new SetCardInfo("Goldbug, Humanity's Ally", 11, Rarity.MYTHIC, mage.cards.g.GoldbugHumanitysAlly.class)); - cards.add(new SetCardInfo("Goldbug, Scrappy Scout", 11, Rarity.MYTHIC, mage.cards.g.GoldbugScrappyScout.class)); - cards.add(new SetCardInfo("Jetfire, Air Guardian", 3, Rarity.MYTHIC, mage.cards.j.JetfireAirGuardian.class)); cards.add(new SetCardInfo("Jetfire, Ingenious Scientist", 3, Rarity.MYTHIC, mage.cards.j.JetfireIngeniousScientist.class)); - cards.add(new SetCardInfo("Megatron, Destructive Force", 12, Rarity.MYTHIC, mage.cards.m.MegatronDestructiveForce.class)); cards.add(new SetCardInfo("Megatron, Tyrant", 12, Rarity.MYTHIC, mage.cards.m.MegatronTyrant.class)); - cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Optimus Prime, Hero", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Optimus Prime, Hero", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ratchet, Field Medic", 2, Rarity.MYTHIC, mage.cards.r.RatchetFieldMedic.class)); - cards.add(new SetCardInfo("Ratchet, Rescue Racer", 2, Rarity.MYTHIC, mage.cards.r.RatchetRescueRacer.class)); - cards.add(new SetCardInfo("Slicer, High-Speed Antagonist", 6, Rarity.MYTHIC, mage.cards.s.SlicerHighSpeedAntagonist.class)); cards.add(new SetCardInfo("Slicer, Hired Muscle", 6, Rarity.MYTHIC, mage.cards.s.SlicerHiredMuscle.class)); cards.add(new SetCardInfo("Starscream, Power Hungry", 5, Rarity.MYTHIC, mage.cards.s.StarscreamPowerHungry.class)); - cards.add(new SetCardInfo("Starscream, Seeker Leader", 5, Rarity.MYTHIC, mage.cards.s.StarscreamSeekerLeader.class)); - cards.add(new SetCardInfo("Ultra Magnus, Armored Carrier", 15, Rarity.MYTHIC, mage.cards.u.UltraMagnusArmoredCarrier.class)); cards.add(new SetCardInfo("Ultra Magnus, Tactician", 15, Rarity.MYTHIC, mage.cards.u.UltraMagnusTactician.class)); } } diff --git a/Mage.Sets/src/mage/sets/URLConventionPromos.java b/Mage.Sets/src/mage/sets/URLConventionPromos.java index 155a5718d2f..da73a7cee08 100644 --- a/Mage.Sets/src/mage/sets/URLConventionPromos.java +++ b/Mage.Sets/src/mage/sets/URLConventionPromos.java @@ -29,7 +29,9 @@ public class URLConventionPromos extends ExpansionSet { cards.add(new SetCardInfo("Kor Skyfisher", 23, Rarity.RARE, mage.cards.k.KorSkyfisher.class)); cards.add(new SetCardInfo("Merfolk Mesmerist", 4, Rarity.RARE, mage.cards.m.MerfolkMesmerist.class)); cards.add(new SetCardInfo("Shepherd of the Lost", "34*", Rarity.UNCOMMON, mage.cards.s.ShepherdOfTheLost.class)); + cards.add(new SetCardInfo("Sokka, Bold Boomeranger", "2025-4", Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class)); cards.add(new SetCardInfo("Stealer of Secrets", 7, Rarity.RARE, mage.cards.s.StealerOfSecrets.class)); cards.add(new SetCardInfo("Steward of Valeron", 1, Rarity.RARE, mage.cards.s.StewardOfValeron.class)); + cards.add(new SetCardInfo("Unbreakable Formation", "2025-5", Rarity.RARE, mage.cards.u.UnbreakableFormation.class)); } } diff --git a/Mage.Sets/src/mage/sets/UniversesWithin.java b/Mage.Sets/src/mage/sets/UniversesWithin.java index 4c79b8ba2de..cdf48b12faf 100644 --- a/Mage.Sets/src/mage/sets/UniversesWithin.java +++ b/Mage.Sets/src/mage/sets/UniversesWithin.java @@ -26,7 +26,6 @@ public final class UniversesWithin extends ExpansionSet { cards.add(new SetCardInfo("Bohn, Beguiling Balladeer", 30, Rarity.RARE, mage.cards.b.BohnBeguilingBalladeer.class)); cards.add(new SetCardInfo("Bjorna, Nightfall Alchemist", 2, Rarity.RARE, mage.cards.b.BjornaNightfallAlchemist.class)); cards.add(new SetCardInfo("Casal, Lurkwood Pathfinder", 29, Rarity.RARE, mage.cards.c.CasalLurkwoodPathfinder.class)); - cards.add(new SetCardInfo("Casal, Pathbreaker Owlbear", 29, Rarity.RARE, mage.cards.c.CasalPathbreakerOwlbear.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("Enkira, Hostile Scavenger", 20, Rarity.MYTHIC, mage.cards.e.EnkiraHostileScavenger.class)); @@ -37,7 +36,6 @@ public final class UniversesWithin extends ExpansionSet { cards.add(new SetCardInfo("Hansk, Slayer Zealot", 22, Rarity.MYTHIC, mage.cards.h.HanskSlayerZealot.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("Immard, the Stormcleaver", 14, Rarity.RARE, mage.cards.i.ImmardTheStormcleaver.class)); cards.add(new SetCardInfo("Jurin, Leading the Charge", 27, Rarity.RARE, mage.cards.j.JurinLeadingTheCharge.class)); cards.add(new SetCardInfo("Maarika, Brutal Gladiator", 15, Rarity.RARE, mage.cards.m.MaarikaBrutalGladiator.class)); diff --git a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2025.java b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2025.java index 5929c33e2fc..edc37e76764 100644 --- a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2025.java +++ b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2025.java @@ -20,15 +20,20 @@ public class WizardsPlayNetwork2025 extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; + cards.add(new SetCardInfo("Carnage, Crimson Chaos", 13, Rarity.RARE, mage.cards.c.CarnageCrimsonChaos.class)); cards.add(new SetCardInfo("Culling Ritual", 4, Rarity.RARE, mage.cards.c.CullingRitual.class)); cards.add(new SetCardInfo("Despark", 2, Rarity.UNCOMMON, mage.cards.d.Despark.class)); cards.add(new SetCardInfo("Dragon's Hoard", "1p", Rarity.RARE, mage.cards.d.DragonsHoard.class, RETRO_ART)); cards.add(new SetCardInfo("Dragonspeaker Shaman", 3, Rarity.RARE, mage.cards.d.DragonspeakerShaman.class)); + cards.add(new SetCardInfo("Gran-Gran", 14, Rarity.RARE, mage.cards.g.GranGran.class)); + cards.add(new SetCardInfo("Mary Jane Watson", 11, Rarity.RARE, mage.cards.m.MaryJaneWatson.class)); cards.add(new SetCardInfo("Monstrous Rage", 9, Rarity.RARE, mage.cards.m.MonstrousRage.class, RETRO_ART)); cards.add(new SetCardInfo("Palladium Myr", 6, Rarity.RARE, mage.cards.p.PalladiumMyr.class, RETRO_ART)); cards.add(new SetCardInfo("Rishkar's Expertise", 1, Rarity.RARE, mage.cards.r.RishkarsExpertise.class, RETRO_ART)); - cards.add(new SetCardInfo("Spectacular Spider-Man", 7, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class)); + cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 10, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class)); cards.add(new SetCardInfo("Trinket Mage", 8, Rarity.RARE, mage.cards.t.TrinketMage.class, RETRO_ART)); + cards.add(new SetCardInfo("Ultimate Green Goblin", 12, Rarity.RARE, mage.cards.u.UltimateGreenGoblin.class)); + cards.add(new SetCardInfo("Yuna, Grand Summoner", 16, Rarity.MYTHIC, mage.cards.y.YunaGrandSummoner.class)); cards.add(new SetCardInfo("Zidane, Tantalus Thief", 5, Rarity.RARE, mage.cards.z.ZidaneTantalusThief.class)); } } diff --git a/Mage.Sets/src/mage/sets/XLNTreasureChest.java b/Mage.Sets/src/mage/sets/XLNTreasureChest.java index 79d13733466..c8fe454fa4d 100644 --- a/Mage.Sets/src/mage/sets/XLNTreasureChest.java +++ b/Mage.Sets/src/mage/sets/XLNTreasureChest.java @@ -20,25 +20,15 @@ public class XLNTreasureChest extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Adanto, the First Fort", 22, Rarity.RARE, mage.cards.a.AdantoTheFirstFort.class)); cards.add(new SetCardInfo("Arguel's Blood Fast", 90, Rarity.RARE, mage.cards.a.ArguelsBloodFast.class)); - cards.add(new SetCardInfo("Azcanta, the Sunken Ruin", 74, Rarity.RARE, mage.cards.a.AzcantaTheSunkenRuin.class)); - cards.add(new SetCardInfo("Conqueror's Foothold", 234, Rarity.RARE, mage.cards.c.ConquerorsFoothold.class)); cards.add(new SetCardInfo("Conqueror's Galleon", 234, Rarity.RARE, mage.cards.c.ConquerorsGalleon.class)); cards.add(new SetCardInfo("Dowsing Dagger", 235, Rarity.RARE, mage.cards.d.DowsingDagger.class)); cards.add(new SetCardInfo("Growing Rites of Itlimoc", 191, Rarity.RARE, mage.cards.g.GrowingRitesOfItlimoc.class)); - cards.add(new SetCardInfo("Itlimoc, Cradle of the Sun", 191, Rarity.RARE, mage.cards.i.ItlimocCradleOfTheSun.class)); cards.add(new SetCardInfo("Legion's Landing", 22, Rarity.RARE, mage.cards.l.LegionsLanding.class)); - cards.add(new SetCardInfo("Lost Vale", 235, Rarity.RARE, mage.cards.l.LostVale.class)); cards.add(new SetCardInfo("Primal Amulet", 243, Rarity.RARE, mage.cards.p.PrimalAmulet.class)); - cards.add(new SetCardInfo("Primal Wellspring", 243, Rarity.RARE, mage.cards.p.PrimalWellspring.class)); cards.add(new SetCardInfo("Search for Azcanta", 74, Rarity.RARE, mage.cards.s.SearchForAzcanta.class)); - cards.add(new SetCardInfo("Spires of Orazca", 249, Rarity.RARE, mage.cards.s.SpiresOfOrazca.class)); - cards.add(new SetCardInfo("Spitfire Bastion", 173, Rarity.RARE, mage.cards.s.SpitfireBastion.class)); - cards.add(new SetCardInfo("Temple of Aclazotz", 90, Rarity.RARE, mage.cards.t.TempleOfAclazotz.class)); cards.add(new SetCardInfo("Thaumatic Compass", 249, Rarity.RARE, mage.cards.t.ThaumaticCompass.class)); - cards.add(new SetCardInfo("Treasure Cove", 250, Rarity.RARE, mage.cards.t.TreasureCove.class)); cards.add(new SetCardInfo("Treasure Map", 250, Rarity.RARE, mage.cards.t.TreasureMap.class)); cards.add(new SetCardInfo("Vance's Blasting Cannons", 173, Rarity.RARE, mage.cards.v.VancesBlastingCannons.class)); - } + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationTriggersAITest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationTriggersAITest.java index a13f26171be..efb6a456eea 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationTriggersAITest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/SimulationTriggersAITest.java @@ -50,21 +50,29 @@ public class SimulationTriggersAITest extends CardTestPlayerBaseWithAIHelps { @Test public void test_DeepglowSkate_PerformanceOnTooManyChoices() { - // bug: game freeze with 100% CPU usage // https://github.com/magefree/mage/issues/9438 - int cardsCount = 2; // 2+ cards will generate too much target options for simulations - int boostMultiplier = (int) Math.pow(2, cardsCount); + int quantity = 1; + String[] cardNames = { + "Island", "Plains", "Swamp", "Mountain", + "Runeclaw Bear", "Absolute Law", "Gilded Lotus", "Alpha Myr" + }; // When Deepglow Skate enters the battlefield, double the number of each kind of counter on any number // of target permanents. - addCard(Zone.HAND, playerA, "Deepglow Skate", cardsCount); // {4}{U} - addCard(Zone.BATTLEFIELD, playerA, "Island", 5 * cardsCount); - // + addCard(Zone.HAND, playerA, "Deepglow Skate", 1); // {4}{U} + // Bloat the battlefield with permanents (possible targets) + for (String card : cardNames) { + addCard(Zone.BATTLEFIELD, playerA, card, quantity); + addCard(Zone.BATTLEFIELD, playerB, card, quantity); + addCard(Zone.BATTLEFIELD, playerC, card, quantity); + addCard(Zone.BATTLEFIELD, playerD, card, quantity); + } + addCard(Zone.BATTLEFIELD, playerA, "Ajani, Adversary of Tyrants", 1); // x4 loyalty addCard(Zone.BATTLEFIELD, playerA, "Ajani, Caller of the Pride", 1); // x4 loyalty addCard(Zone.BATTLEFIELD, playerB, "Ajani Goldmane", 1); // x4 loyalty addCard(Zone.BATTLEFIELD, playerB, "Ajani, Inspiring Leader", 1); // x5 loyalty - // + // Players can't activate planeswalkers' loyalty abilities. addCard(Zone.BATTLEFIELD, playerA, "The Immortal Sun", 1); // disable planeswalkers usage by AI @@ -75,9 +83,9 @@ public class SimulationTriggersAITest extends CardTestPlayerBaseWithAIHelps { setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Deepglow Skate", cardsCount); - assertCounterCount(playerA, "Ajani, Adversary of Tyrants", CounterType.LOYALTY, 4 * boostMultiplier); - assertCounterCount(playerA, "Ajani, Caller of the Pride", CounterType.LOYALTY, 4 * boostMultiplier); + assertPermanentCount(playerA, "Deepglow Skate", 1); + assertCounterCount(playerA, "Ajani, Adversary of Tyrants", CounterType.LOYALTY, 4 * 2); + assertCounterCount(playerA, "Ajani, Caller of the Pride", CounterType.LOYALTY, 4 * 2); assertCounterCount(playerB, "Ajani Goldmane", CounterType.LOYALTY, 4); assertCounterCount(playerB, "Ajani, Inspiring Leader", CounterType.LOYALTY, 5); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java index 3a58e0dad27..f2970d1bc14 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DayNightTest.java @@ -1,6 +1,7 @@ package org.mage.test.cards.abilities.keywords; import mage.cards.Card; +import mage.cards.DoubleFacedCard; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -67,7 +68,7 @@ public class DayNightTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, ruffian); runCode("copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { - Card card = currentGame.getCards().stream().filter(c -> c.getName().equals(ruffian)).findFirst().orElse(null); + Card card = currentGame.getCards().stream().filter(c -> c.getName().equals(ruffian) && c instanceof DoubleFacedCard).findFirst().orElse(null); Assert.assertNotNull(card); Assert.assertNotNull(card.getSecondCardFace()); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java index f2e12c3e5e0..b81b26e844b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/IncubateTest.java @@ -200,23 +200,8 @@ public class IncubateTest extends CardTestPlayerBase { setChoice(playerA, true); // use copy setChoice(playerA, "Phyrexian Token"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 2); - - // kill original token - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy"); - addTarget(playerA, "Phyrexian Token[no copy]"); - waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after kill", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); - showBattlefield("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA); - - // try to transform back side (nothing happen) - // 701.28c - // If a spell or ability instructs a player to transform a permanent that isn’t represented by a - // transforming token or a transforming double-faced card, nothing happens. - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", "Phyrexian Token"); - waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Incubator Token", 0); - checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); + checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1); + // copy dies to state based actions setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); 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 04417cc619c..c8ccc2e413d 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 @@ -1,17 +1,290 @@ package org.mage.test.cards.abilities.keywords; +import mage.ObjectColor; +import mage.abilities.common.SagaAbility; +import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.constants.CardType; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * @author LevelX2 */ public class TransformTest extends CardTestPlayerBase { + + /* + Silvercoat Lion + {1}{W} + Creature - Cat + + 2/2 + */ + private static final String silvercoatLion = "Silvercoat Lion"; + + /* + Lightning Bolt + {R} + Instant + Lightning Bolt deals 3 damage to any target. + */ + private static final String lightningBolt = "Lightning Bolt"; + + /* + Azusa's Many Journeys + {1}{G} + Enchantment - Saga + (As this Saga enters and after your draw step, add a lore counter.) + I - You may play an additional land this turn. + II - You gain 3 life. + III - Exile this Saga, then return it to the battlefield transformed under your control. + Likeness of the Seeker + + Enchantment Creature - Human Monk + Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control. + 3/3 + */ + private static final String azusasManyJourneys = "Azusa's Many Journeys"; + private static final String likenessOfTheSeeker = "Likeness of the Seeker"; + + /* + Liliana, Heretical Healer + {1}{B}{B} + Legendary Creature - Human Cleric + Lifelink + Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. + 2/3 + + Liliana, Defiant Necromancer + Legendary Planeswalker - Liliana + +2: Each player discards a card. + -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. + -8: You get an emblem with "Whenever a creature you control dies, return it to the battlefield under your control at the beginning of the next end step." + */ + private static final String lilianaHereticalHealer = "Liliana, Heretical Healer"; + private static final String lilianaDefiantNecromancer = "Liliana, Defiant Necromancer"; + + /* + Languish + {2}{B}{B} + Sorcery + All creatures get -4/-4 until end of turn. + */ + private static final String languish = "Languish"; + + /* + Nissa, Vastwood Seer + {2}{G} + Legendary Creature - Elf Scout + When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. + Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. + 2/2 + + Nissa, Sage Animist + Legendary Planeswalker - Nissa + +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. + -2: Put a legendary 4/4 green Elemental creature token named Ashaya, the Awoken World onto the battlefield. + -7: Untap up to six target lands. They become 6/6 Elemental creatures. They're still lands. + */ + private static final String nissaVastwoodSeer = "Nissa, Vastwood Seer"; + private static final String nissaSageAnimist = "Nissa, Sage Animist"; + + /* + Fireball + {X}{R} + Sorcery + Fireball deals X damage divided evenly, rounded down, among any number of target creatures and/or players. + Fireball costs {1} more to cast for each target beyond the first. + */ + private static final String fireball = "Fireball"; + + /* + Infernal Scarring + {1}{B} + Enchantment - Aura + Enchant creature + Enchanted creature gets +2/+0 and has "When this creature dies, draw a card." + */ + private static final String infernalScarring = "Infernal Scarring"; + + /* + Autumnal Gloom + {2}{G} + Enchantment + {B}: Put the top card of your library into your graveyard. + Delirium - At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. + + Ancient of the Equinox + Creature - Treefolk + Trample, hexproof + 4/4 + */ + private static final String autumnalGloom = "Autumnal Gloom"; + private static final String ancientOfTheEquinox = "Ancient of the Equinox"; + + /* + Huntmaster of the Fells + {2}{R}{G} + Creature - Human Werewolf + Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, put a 2/2 green Wolf creature token onto the battlefield and you gain 2 life. + At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells. + 2/2 + + Ravager of the Fells + Creature - Werewolf + Trample + Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. + At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. + 4/4 + */ + private static final String huntmasterOfTheFells = "Huntmaster of the Fells"; + private static final String ravagerOfTheFells = "Ravager of the Fells"; + + /* + Eldrazi Displacer + {2}{W} + Creature - Eldrazi + Devoid + {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. + 3/3 + */ + private static final String eldraziDisplacer = "Eldrazi Displacer"; + + /* + Howlpack Piper + {3}{G} + Creature - Human Werewolf + This spell can't be countered. + {1}{G}, {T}: You may put a creature card from your hand onto the battlefield. If it's a Wolf or Werewolf, untap Howlpack Piper. Activate only as a sorcery. + Daybound + 2/2 + + Wildsong Howler + Creature - Werewolf + 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. + Nightbound + 4/4 + */ + private static final String howlpackPiper = "Howlpack Piper"; + private static final String wildsongHowler = "Wildsong Howler"; + + /* + Thing in the Ice + {1}{U} + Creature - Horror + Defender + Thing in the Ice enters the battlefield with four ice counters on it. + Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. Then if it has no ice counters on it, transform it. + + Awoken Horror + Creature - Kraken Horror + When this creature transforms into Awoken Horrow, return all non-Horror creatures to their owners' hands. + 7/8 + */ + private static final String thingInTheIce = "Thing in the Ice"; + private static final String awokenHorror = "Awoken Horror"; + + /* + Banners Raised + {R} + Instant + Creatures you control get +1/+0 until end of turn. + */ + private static final String bannersRaised = "Banners Raised"; + + /* + Phantasmal Image + {1}{U} + Creature - Illusion + You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains "When this creature becomes the target of a spell or ability, sacrifice it." + */ + private static final String phantasmalImage = "Phantasmal Image"; + + /* + Delver of Secrets + {U} + Creature - Human Wizard + At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets. + 1/1 + + Insectile Aberration + Creature - Human Insect + Flying + 3/2 + */ + private static final String delverOfSecrets = "Delver of Secrets"; + private static final String insectileAberration = "Insectile Aberration"; + + /* + Moonmist + {1}{G} + Instant + Transform all Humans. Prevent all combat damage that would be dealt this turn by creatures other than Werewolves and Wolves. (Only double-faced cards can be transformed.) + */ + private static final String moonmist = "Moonmist"; + + /* + Maskwood Nexus + {4} + Artifact + Creatures you control are every creature type. The same is true for creature spells you control and creature cards you own that aren't on the battlefield. + {3}, {T}: Create a 2/2 blue Shapeshifter creature token with changeling. + */ + private static final String maskwoodNexus = "Maskwood Nexus"; + + /* + Dress Down + {1}{U} + Enchantment + Flash + When Dress Down enters the battlefield, draw a card. + Creatures lose all abilities. + At the beginning of the end step, sacrifice Dress Down. + */ + private static final String dressDown = "Dress Down"; + + /* + Baithook Angler + {1}{U} + Creature - Human Peasant + Disturb {1}{U} + 2/1 + + Hook-Haunt Drifter + Creature - Spirit + Flying + If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead. + 1/2 + */ + private static final String baithookAngler = "Baithook Angler"; + private static final String hookHauntDrifter = "Hook-Haunt Drifter"; + + /* + Croaking Counterpart + {1}{G}{U} + Sorcery + Create a token that's a copy of target non-Frog creature, except it's a 1/1 green Frog. + Flashback {3}{G}{U} + */ + private static final String croakingCounterpart = "Croaking Counterpart"; + + /* + Abnormal Endurance + {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." + */ + private static final String abnormalEndurance = "Abnormal Endurance"; + @Test public void NissaVastwoodSeerTest() { @@ -22,13 +295,13 @@ public class TransformTest extends CardTestPlayerBase { // When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library. // Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control. - addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer"); + addCard(Zone.HAND, playerA, nissaVastwoodSeer); addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); // {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library. addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G} - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nissaVastwoodSeer, true); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp"); @@ -40,38 +313,38 @@ public class TransformTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Rootrunner", 1); - assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0); - assertPermanentCount(playerA, "Nissa, Sage Animist", 1); + assertPermanentCount(playerA, nissaVastwoodSeer, 0); + assertPermanentCount(playerA, nissaSageAnimist, 1); - assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 4); + assertCounterCount(nissaSageAnimist, CounterType.LOYALTY, 4); assertPermanentCount(playerA, "Forest", 6); assertPermanentCount(playerA, "Swamp", 1); } @Test public void LilianaHereticalHealer() { - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); // Lifelink // Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. - addCard(Zone.HAND, playerA, "Liliana, Heretical Healer"); + addCard(Zone.HAND, playerA, lilianaHereticalHealer); - addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.HAND, playerB, lightningBolt); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Liliana, Heretical Healer"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lilianaHereticalHealer); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, silvercoatLion); setStopAt(1, PhaseStep.DECLARE_ATTACKERS); execute(); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); - assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerA, silvercoatLion, 1); + assertGraveyardCount(playerB, lightningBolt, 1); - assertPermanentCount(playerA, "Liliana, Heretical Healer", 0); - assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); - assertCounterCount("Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); + assertPermanentCount(playerA, lilianaHereticalHealer, 0); + assertPermanentCount(playerA, lilianaDefiantNecromancer, 1); + assertCounterCount(lilianaDefiantNecromancer, CounterType.LOYALTY, 3); assertPermanentCount(playerA, "Zombie Token", 1); } @@ -84,45 +357,45 @@ public class TransformTest extends CardTestPlayerBase { */ @Test public void LilianaHereticalHealer2() { - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1); // Lifelink // Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield. - addCard(Zone.BATTLEFIELD, playerA, "Liliana, Heretical Healer"); + addCard(Zone.BATTLEFIELD, playerA, lilianaHereticalHealer); // All creatures get -4/-4 until end of turn. - addCard(Zone.HAND, playerB, "Languish"); + addCard(Zone.HAND, playerB, languish); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 4); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Languish"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, languish); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); - assertGraveyardCount(playerB, "Languish", 1); - assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 0); + assertGraveyardCount(playerB, languish, 1); + assertPermanentCount(playerA, lilianaDefiantNecromancer, 0); assertPermanentCount(playerA, "Zombie Token", 0); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); - assertGraveyardCount(playerA, "Liliana, Heretical Healer", 1); + assertGraveyardCount(playerA, silvercoatLion, 1); + assertGraveyardCount(playerA, lilianaHereticalHealer, 1); } @Test public void TestEnchantmentToCreature() { - addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); - addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1); - addCard(Zone.GRAVEYARD, playerA, "Fireball", 1); - addCard(Zone.GRAVEYARD, playerA, "Infernal Scarring", 1); + addCard(Zone.GRAVEYARD, playerA, silvercoatLion, 1); + addCard(Zone.GRAVEYARD, playerA, lightningBolt, 1); + addCard(Zone.GRAVEYARD, playerA, fireball, 1); + addCard(Zone.GRAVEYARD, playerA, infernalScarring, 1); // {B}: Put the top card of your library into your graveyard. // Delirium &mdash At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. - addCard(Zone.BATTLEFIELD, playerA, "Autumnal Gloom"); + addCard(Zone.BATTLEFIELD, playerA, autumnalGloom); setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Autumnal Gloom", 0); - assertPermanentCount(playerA, "Ancient of the Equinox", 1); + assertPermanentCount(playerA, autumnalGloom, 0); + assertPermanentCount(playerA, ancientOfTheEquinox, 1); } /** @@ -138,6 +411,7 @@ public class TransformTest extends CardTestPlayerBase { */ @Test public void testCultOfTheWaxingMoon() { + setStrictChooseMode(true); // Whenever a permanent you control transforms into a non-Human creature, put a 2/2 green Wolf creature token onto the battlefield. addCard(Zone.BATTLEFIELD, playerA, "Cult of the Waxing Moon"); // {1}{G} - Human Werewolf @@ -151,6 +425,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 Token", 1); // wolf token created + assertAbilityCount(playerA, "Timber Shredder", WerewolfFrontTriggeredAbility.class, 0); // no front face ability } /** @@ -184,18 +459,42 @@ public class TransformTest extends CardTestPlayerBase { } @Test - public void testStartledAwakeMoonmist() { - addCard(Zone.HAND, playerA, "Startled Awake"); - addCard(Zone.HAND, playerA, "Moonmist"); - addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11); - addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus"); + public void testPersistentNightmareTrigger() { + // Target opponent puts the top thirteen cards of their library into their graveyard. + // {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery. + addCard(Zone.HAND, playerA, "Startled Awake"); // SORCERY {2}{U}{U}" + addCard(Zone.BATTLEFIELD, playerA, "Island", 9); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + attack(3, playerA, "Persistent Nightmare"); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.COMBAT_DAMAGE); + execute(); + + assertGraveyardCount(playerB, 13); + assertGraveyardCount(playerA, "Startled Awake", 0); + assertPermanentCount(playerA, "Persistent Nightmare", 0); // Night-side card of Startled Awake + assertHandCount(playerA, "Startled Awake", 1); + } + + @Test + public void testStartledAwakeMoonmist() { + addCard(Zone.HAND, playerA, "Startled Awake"); + addCard(Zone.HAND, playerA, moonmist); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11); + addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -241,6 +540,25 @@ public class TransformTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Lambholt Pacifist", 1); } + @Test + public void testDisturbExile() { + addCard(Zone.GRAVEYARD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + addCard(Zone.HAND, playerB, lightningBolt); + + // Disturb {1}{U} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, hookHauntDrifter + " using Disturb"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, lightningBolt, hookHauntDrifter); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, hookHauntDrifter, 0); + assertExileCount(playerA, baithookAngler, 1); + } + /** * Mirror Mockery copies the front face of a Transformed card rather than * the current face. @@ -251,7 +569,7 @@ public class TransformTest extends CardTestPlayerBase { * Trespasser. */ @Test - public void testTransformCopyrnansformed() { + public void testTransformCopyTransformed() { // Skulk (This creature can't be blocked by creatures with greater power.) // When Uninvited Geist deals combat damage to a player, transform it. addCard(Zone.BATTLEFIELD, playerA, "Uninvited Geist"); // Creature 2/2 {2}{U} @@ -272,7 +590,7 @@ public class TransformTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.COMBAT_DAMAGE); execute(); - assertLife(playerB, 15); + assertLife(playerB, 20 - 2 - 3); assertPermanentCount(playerB, "Mirror Mockery", 1); assertPermanentCount(playerA, "Unimpeded Trespasser", 1); @@ -293,16 +611,16 @@ public class TransformTest extends CardTestPlayerBase { // Transformed side: Avacyn, the Purifier - Creature 6/5 // Flying // When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent. - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); - addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerA, silvercoatLion); + addCard(Zone.HAND, playerA, lightningBolt); addCard(Zone.BATTLEFIELD, playerA, "Mountain"); // Devoid // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. - addCard(Zone.BATTLEFIELD, playerB, "Eldrazi Displacer", 1); + addCard(Zone.BATTLEFIELD, playerB, eldraziDisplacer, 1); addCard(Zone.BATTLEFIELD, playerB, "Wastes", 3); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, lightningBolt, silvercoatLion); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{C}", "Archangel Avacyn"); @@ -310,10 +628,10 @@ public class TransformTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); - assertGraveyardCount(playerA, "Lightning Bolt", 1); - assertGraveyardCount(playerA, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, lightningBolt, 1); + assertGraveyardCount(playerA, silvercoatLion, 1); - assertPermanentCount(playerB, "Eldrazi Displacer", 1); + assertPermanentCount(playerB, eldraziDisplacer, 1); assertPermanentCount(playerA, "Avacyn, the Purifier", 0); assertPermanentCount(playerA, "Archangel Avacyn", 1); } @@ -355,20 +673,20 @@ public class TransformTest extends CardTestPlayerBase { // Ravager of the Fells // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G} + addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); // Devoid // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. - addCard(Zone.HAND, playerB, "Eldrazi Displacer", 1); // Creature {2}{W} + addCard(Zone.HAND, playerB, eldraziDisplacer, 1); // Creature {2}{W} addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); addCard(Zone.BATTLEFIELD, playerB, "Wastes", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells"); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Eldrazi Displacer"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, eldraziDisplacer); - activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", "Huntmaster of the Fells", "At the beginning of each upkeep"); + activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", huntmasterOfTheFells, "At the beginning of each upkeep"); setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -376,11 +694,11 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerA, 24); assertPermanentCount(playerA, "Wolf Token", 2); - assertPermanentCount(playerB, "Eldrazi Displacer", 1); + assertPermanentCount(playerB, eldraziDisplacer, 1); - assertPermanentCount(playerA, "Ravager of the Fells", 0); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2); + assertPermanentCount(playerA, ravagerOfTheFells, 0); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); + assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2); assertTappedCount("Plains", true, 2); assertTappedCount("Wastes", true, 1); } @@ -392,50 +710,50 @@ public class TransformTest extends CardTestPlayerBase { // Ravager of the Fells // Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls. // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells. - addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G} - addCard(Zone.HAND, playerA, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G} + addCard(Zone.HAND, playerA, silvercoatLion, 2); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells", true); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion", true); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells, true); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion, true); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion); setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); assertLife(playerA, 24); assertLife(playerB, 18); assertPermanentCount(playerA, "Wolf Token", 2); - assertPermanentCount(playerA, "Silvercoat Lion", 2); - assertPermanentCount(playerA, "Ravager of the Fells", 0); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2); + assertPermanentCount(playerA, silvercoatLion, 2); + assertPermanentCount(playerA, ravagerOfTheFells, 0); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); + assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2); } @Test public void testWildsongHowlerTrigger() { // The only Daybound/Nightbound card with a Transforms trigger on the back side removeAllCardsFromLibrary(playerA); - addCard(Zone.HAND, playerA, "Howlpack Piper", 2); // Creature {2}{R}{G} - addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 50); + addCard(Zone.HAND, playerA, howlpackPiper, 2); // Creature {2}{R}{G} + addCard(Zone.LIBRARY, playerA, silvercoatLion, 50); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper); setChoice(playerA, true); //Transform trigger - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, silvercoatLion); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper"); + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper); setChoice(playerA, true); //ETB trigger - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, silvercoatLion); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); setStrictChooseMode(true); execute(); - assertPermanentCount(playerA, "Wildsong Howler", 2); - assertPermanentCount(playerA, "Howlpack Piper", 0); // They should be both transformed - assertHandCount(playerA, "Silvercoat Lion", 3); + assertPermanentCount(playerA, wildsongHowler, 2); + assertPermanentCount(playerA, howlpackPiper, 0); // They should be both transformed + assertHandCount(playerA, silvercoatLion, 3); assertHandCount(playerA, 3); //The two Silvercoat Lions from triggers and 1 from natural card draw } @@ -455,37 +773,37 @@ public class TransformTest extends CardTestPlayerBase { // Thing in the Ice enters the battlefield with four ice counters on it. // Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. // Then if it has no ice counters on it, transform it. - addCard(Zone.HAND, playerA, "Thing in the Ice"); // Creature {1}{U} + addCard(Zone.HAND, playerA, thingInTheIce); // Creature {1}{U} // Creatures you control get +1/+0 until end of turn. - addCard(Zone.HAND, playerA, "Banners Raised", 4); // Creature {R} + addCard(Zone.HAND, playerA, bannersRaised, 4); // Creature {R} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); addCard(Zone.BATTLEFIELD, playerA, "Island", 1); // You may have Phantasmal Image enter the battlefield as a copy of any creature // on the battlefield, except it's an Illusion in addition to its other types and // it has "When this creature becomes the target of a spell or ability, sacrifice it." - addCard(Zone.HAND, playerB, "Phantasmal Image", 1); // Creature {1}{U} + addCard(Zone.HAND, playerB, phantasmalImage, 1); // Creature {1}{U} addCard(Zone.BATTLEFIELD, playerB, "Island", 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thing in the Ice"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, thingInTheIce); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, phantasmalImage); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertLife(playerA, 20); - assertGraveyardCount(playerA, "Banners Raised", 4); - assertPermanentCount(playerA, "Thing in the Ice", 0); - assertPermanentCount(playerA, "Awoken Horror", 1); - assertPowerToughness(playerA, "Awoken Horror", 7, 8); + assertGraveyardCount(playerA, bannersRaised, 4); + assertPermanentCount(playerA, thingInTheIce, 0); + assertPermanentCount(playerA, awokenHorror, 1); + assertPowerToughness(playerA, awokenHorror, 7, 8); - assertPermanentCount(playerB, "Awoken Horror", 1); - assertPowerToughness(playerB, "Awoken Horror", 7, 8); + assertPermanentCount(playerB, awokenHorror, 1); + assertPowerToughness(playerB, awokenHorror, 7, 8); } @@ -493,45 +811,45 @@ public class TransformTest extends CardTestPlayerBase { public void testMoonmistDelver() { addCard(Zone.BATTLEFIELD, playerA, "Island"); addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); - addCard(Zone.HAND, playerA, "Delver of Secrets"); - addCard(Zone.HAND, playerA, "Moonmist", 2); + addCard(Zone.HAND, playerA, delverOfSecrets); + addCard(Zone.HAND, playerA, moonmist, 2); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Delver of Secrets"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, delverOfSecrets); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Delver of Secrets", 0); - assertPermanentCount(playerA, "Insectile Aberration", 1); + assertPermanentCount(playerA, delverOfSecrets, 0); + assertPermanentCount(playerA, insectileAberration, 1); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Delver of Secrets", 1); - assertPermanentCount(playerA, "Insectile Aberration", 0); + assertPermanentCount(playerA, delverOfSecrets, 1); + assertPermanentCount(playerA, insectileAberration, 0); } @Test public void testMoonmistHuntmasterDressdown() { addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6); - addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells"); //Has on-transform triggers - addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus"); //Make back side human + addCard(Zone.BATTLEFIELD, playerA, huntmasterOfTheFells); //Has on-transform triggers + addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus); //Make back side human - addCard(Zone.HAND, playerA, "Dress Down"); //Creatures lose all abilities - addCard(Zone.HAND, playerA, "Moonmist", 2); + addCard(Zone.HAND, playerA, dressDown); //Creatures lose all abilities + addCard(Zone.HAND, playerA, moonmist, 2); - castSpell(1, PhaseStep.UPKEEP, playerA, "Dress Down"); + castSpell(1, PhaseStep.UPKEEP, playerA, dressDown); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist"); - checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, "Ravager of the Fells", 1); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist); + checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, ravagerOfTheFells, 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -539,8 +857,71 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertGraveyardCount(playerA, "Dress Down", 1); - assertPermanentCount(playerA, "Huntmaster of the Fells", 1); + assertGraveyardCount(playerA, dressDown, 1); + assertPermanentCount(playerA, huntmasterOfTheFells, 1); assertPermanentCount(playerA, 6+1+1); } + + @Test + public void testTokenCopyTransformed() { + addCard(Zone.GRAVEYARD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5); + addCard(Zone.HAND, playerA, croakingCounterpart); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, croakingCounterpart, hookHauntDrifter); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + for (Permanent token : currentGame.getBattlefield().getActivePermanents(playerA.getId(), currentGame)) { + if (!(token instanceof PermanentToken)) { + continue; + } + assertTrue(token.getSubtype(currentGame).contains(SubType.FROG)); + assertEquals(ObjectColor.GREEN, token.getColor(currentGame)); + } + } + + @Test + public void testFrontSaga() { + addCard(Zone.BATTLEFIELD, playerA, azusasManyJourneys); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, azusasManyJourneys, 0); + assertPermanentCount(playerA, likenessOfTheSeeker, 1); + assertPowerToughness(playerA, likenessOfTheSeeker, 3, 3); + assertAbilityCount(playerA, likenessOfTheSeeker, SagaAbility.class, 0); // does not have saga ability + assertLife(playerA, 20 + 3); + } + + /** + * testing if a double faced card gains a death trigger, it still works correctly + */ + @Test + public void testDiesTrigger() { + addCard(Zone.BATTLEFIELD, playerA, baithookAngler); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, abnormalEndurance); + + addCard(Zone.HAND, playerB, lightningBolt); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, baithookAngler); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, abnormalEndurance, baithookAngler, lightningBolt); + + setStopAt(1, PhaseStep.DECLARE_ATTACKERS); + execute(); + + assertGraveyardCount(playerA, baithookAngler, 0); + assertGraveyardCount(playerB, lightningBolt, 1); + + assertPermanentCount(playerA, baithookAngler, 1); + assertTrue(getPermanent(baithookAngler, playerA).isTapped()); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/FlameheartWerewolfTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/FlameheartWerewolfTest.java index 4c617a1cf84..23de9f35fbc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/FlameheartWerewolfTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/FlameheartWerewolfTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.oneshot.damage; import mage.constants.PhaseStep; @@ -38,7 +37,7 @@ public class FlameheartWerewolfTest extends CardTestPlayerBase { // both should die assertPermanentCount(playerA, "Flameheart Werewolf", 0); - assertExileCount("Flameheart Werewolf", 1); // exiled by Kalitas + assertExileCount("Kessig Forgemaster", 1); // exiled by Kalitas assertPermanentCount(playerB, "Kalitas, Traitor of Ghet", 0); assertGraveyardCount(playerB, "Kalitas, Traitor of Ghet", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java index 51749e04da0..0a5cc2b300e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java @@ -266,4 +266,29 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { assertType(urborgtoy, CardType.LAND, SubType.ISLAND); assertType("Mountain", CardType.LAND, SubType.ISLAND); } + @Test + public void testOrcishFarmer() { + // {T}: Target land becomes a Swamp until its controller's next untap step + addCard(Zone.BATTLEFIELD, playerA, "Orcish Farmer", 2); + + addCard(Zone.BATTLEFIELD, playerA, "Plains"); + addCard(Zone.BATTLEFIELD, playerB, "Reliquary Tower"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target", "Plains"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target", "Reliquary Tower"); + checkSubType("Plains is Swamp on same turn", 1, PhaseStep.END_TURN, playerA, "Plains", SubType.SWAMP, true); + checkSubType("Plains is no longer Plains on same turn", 1, PhaseStep.END_TURN, playerA, "Plains", SubType.PLAINS, false); + checkSubType("Reliquary Tower is Swamp on same turn", 1, PhaseStep.END_TURN, playerB, "Reliquary Tower", SubType.SWAMP, true); + + checkSubType("Plains is Swamp on next turn", 2, PhaseStep.UPKEEP, playerA, "Plains", SubType.SWAMP, true); + checkSubType("Plains is no longer Plains on next turn", 2, PhaseStep.UPKEEP, playerA, "Plains", SubType.PLAINS, false); + checkSubType("Reliquary Tower no longer Swamp on next turn", 2, PhaseStep.UPKEEP, playerB, "Reliquary Tower", SubType.SWAMP, false); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.UPKEEP); + execute(); + + assertNotSubtype("Plains", SubType.SWAMP); + assertSubtype("Plains", SubType.PLAINS); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java index 32a18f84bbb..26cc4aa5df6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java @@ -3,10 +3,13 @@ package org.mage.test.cards.copy; import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.game.permanent.Permanent; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * * @author LevelX2 @@ -85,4 +88,22 @@ public class CopyCreatureCardToTokenImplTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Thrashing Brontodon", 1); assertType("Thrashing Brontodon", CardType.ARTIFACT, true); } + + @Test + public void testTokenCopyTransformedHasSecondFaceWithModifications() { + setStrictChooseMode(true); + + String hookHauntDrifter = "Hook-Haunt Drifter"; + addCard(Zone.GRAVEYARD, playerA, "Baithook Angler"); + addCard(Zone.BATTLEFIELD, playerB, "Faerie Artisans", 1); + addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + Permanent token = getPermanent(hookHauntDrifter, playerB); + assertTrue(token.getCardType(currentGame).contains(CardType.ARTIFACT)); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java index 257cae4f572..07909a33372 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java @@ -907,6 +907,32 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase { execute(); } + @Test + public void test_Copy_AsSpell_Backside() { + addCard(Zone.HAND, playerA, "Alrund, God of the Cosmos", 1); // {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + // + // Copy target creature spell you control, except it isn't legendary if the spell is legendary. + addCard(Zone.HAND, playerA, "Double Major", 1); // {G}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + + // cast mdf card + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 2); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven"); + // prepare copy of spell + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Hakka, Whispering Raven", "Hakka, Whispering Raven"); + checkStackSize("before copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + checkStackSize("after copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven", 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + } + @Test public void test_Copy_AsCloneFromPermanent() { addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R} @@ -1138,8 +1164,8 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase { Assert.assertNotNull(permanent); // MDFC on battlefield has only one side (not transformable) - Assert.assertFalse("server must not be transformable", permanent.isTransformable()); - Assert.assertNull("server must have not other side", permanent.getOtherFace()); +// Assert.assertFalse("server must not be transformable", permanent.isTransformable()); +// Assert.assertNull("server must have not other side", permanent.getOtherFace()); List rules = permanent.getRules(game); Assert.assertTrue("server must ignore side 2 - untap ability", rules.stream().noneMatch(r -> r.contains("Untap"))); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java new file mode 100644 index 00000000000..b9d380b5c23 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/RoomCardTest.java @@ -0,0 +1,1077 @@ +package org.mage.test.cards.cost.splitcards; + +import mage.constants.*; +import mage.view.CardView; +import mage.view.GameView; +import mage.view.PlayerView; +import org.junit.Test; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author oscscull + */ +public class RoomCardTest extends CardTestPlayerBase { + + /* + Bottomless Pool // Locker Room + {U} + Enchantment - Room + When you unlock this door, return up to one target creature to its owner's hand. + (You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.) + Locker Room + {4}{U} + Enchantment -- Room + Whenever one or more creatures you control deal combat damage to a player, draw a card. + (You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.) + */ + private static final String bottomlessPoolLockerRoom = "Bottomless Pool // Locker Room"; + private static final String bottomlessPool = "Bottomless Pool"; + public static final String lockerRoom = "Locker Room"; + + + @Test + public void testCardViewLeftHalf() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true); + addTarget(playerA, TestPlayer.TARGET_SKIP); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(bottomlessPool)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // unlock ability + unlock trigger from right half + info + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("{U}", cardView.getManaCostStr(), "Mana cost must be from left half"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewRightHalf() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom, true); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(lockerRoom)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // unlock ability + unlock trigger from left half + info + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("{4}{U}", cardView.getManaCostStr(), "Mana cost must be from right half"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewBothHalves() { + setStrictChooseMode(true); + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true); + addTarget(playerA, TestPlayer.TARGET_SKIP); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().equals(bottomlessPoolLockerRoom)) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locker Room card view must be found on battlefield"); + // permanent should have 3 abilities + // 1 ability from both halves + // no unlock abilities + // 1 info + String manaCost = getPermanent(bottomlessPoolLockerRoom) + .getManaCost() + .stream() + .map(Objects::toString) + .reduce("", String::concat); + assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals(manaCost, cardView.getManaCostStr(), "Mana cost must be combined from both halves"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + @Test + public void testCardViewFullyLocked() { + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { + GameView gameView = getGameView(playerA); + PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null); + assertNotNull(playerView, "Player view must be found"); + CardView cardView = playerView.getBattlefield().values() + .stream() + .filter(pv -> pv.getName().isEmpty()) + .findFirst() + .orElse(null); + assertNotNull(cardView, "Locked room card view must be found on battlefield"); + // permanent should have 3 abilities + // 1 info + // two unlock abilities + assertEquals(3, cardView.getRules().size(), "Locked room must have 3 rules, has: " + cardView.getRules().size()); + assertEquals("", cardView.getManaCostStr(), "Mana cost must be empty"); + StringBuilder sb = new StringBuilder("\n" + cardView.getName()); + sb.append("\n - Types: ").append(cardView.getCardTypes()); + sb.append("\n - Subtypes: ").append(cardView.getSubTypes()); + sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr()); + sb.append("\n - Abilities: "); + cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule)); + logger.info(sb.toString()); + }); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + } + + // Bottomless pool is cast. It unlocks, and the trigger to return a creature + // should bounce one of two grizzly bears. + @Test + public void testBottomlessPoolETB() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2); + + checkPlayableAbility("playerA can cast Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, + "Cast Bottomless Pool", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + + // Target one of playerB's "Grizzly Bears" with the return effect. + addTarget(playerA, "Grizzly Bears"); + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + // Assertions: + // Verify that one "Grizzly Bears" is still on playerB's battlefield. + assertPermanentCount(playerB, "Grizzly Bears", 1); + // Verify that one "Grizzly Bears" has been returned to playerB's hand. + assertHandCount(playerB, "Grizzly Bears", 1); + // Verify that "Bottomless Pool" is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPool, 1); + // Verify that "Bottomless Pool" is an Enchantment. + assertType(bottomlessPool, CardType.ENCHANTMENT, true); + // Verify that "Bottomless Pool" has the Room subtype. + assertSubtype(bottomlessPool, SubType.ROOM); + } + + // Locker room is cast. It enters, and gives a coastal piracy effect that + // triggers on damage. + @Test + public void testLockerRoomCombatDamageTrigger() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + // Cards to be drawn + addCard(Zone.LIBRARY, playerA, "Plains", 2); // Expected cards to be drawn + + // 2 attackers + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); + attack(1, playerA, "Memnite"); + attack(1, playerA, "Memnite"); + // After combat damage, Memnites dealt combat damage to playerB (1 damage * 2). + // 2 Locker Room triggers should go on the stack. + checkStackSize("Locker Room trigger must be on the stack", 1, PhaseStep.COMBAT_DAMAGE, playerA, 2); + checkStackObject("Locker Room trigger must be correct", 1, PhaseStep.COMBAT_DAMAGE, playerA, + "Whenever a creature you control deals combat damage to an opponent, draw a card.", 2); + + // Stop at the end of the combat phase to check triggers. + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + // Assertions after the first execute() (Locker Room and creatures are on + // battlefield, combat resolved): + assertPermanentCount(playerA, lockerRoom, 1); + assertType(lockerRoom, CardType.ENCHANTMENT, true); + assertSubtype(lockerRoom, SubType.ROOM); + assertPermanentCount(playerA, "Memnite", 2); + + setStrictChooseMode(true); + execute(); // Resolve the Locker Room trigger. + + // PlayerA should have drawn two plains cards + assertHandCount(playerA, "Plains", 2); + } + + @Test + public void testBottomlessPoolUnlock() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + // 2 creatures owned by player A + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}: Unlock the left half.", true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}: Unlock the left half."); + addTarget(playerA, "Memnite"); + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that one "Memnite" is still on playerA's battlefield. + assertPermanentCount(playerA, "Memnite", 1); + // Verify that one "Memnite" has been returned to playerA's hand. + assertHandCount(playerA, "Memnite", 1); + // Verify that bottomlessPoolLockerRoom is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + // Verify that bottomlessPoolLockerRoom is an Enchantment. + assertType(bottomlessPoolLockerRoom, CardType.ENCHANTMENT, true); + // Verify that bottomlessPoolLockerRoom has the Room subtype. + assertSubtype(bottomlessPoolLockerRoom, SubType.ROOM); + } + + @Test + public void testFlickerNameAndManaCost() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Felidar Guardian"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + // creatures owned by player A + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + // resolve spell cast + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // unlock and trigger bounce on Memnite + addTarget(playerA, "Memnite"); + // resolve bounce + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Felidar Guardian"); + // resolve spell cast + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // etb and flicker on Bottomless Pool + setChoice(playerA, "Yes"); + addTarget(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that one "Memnite" has been returned to playerA's hand. + assertHandCount(playerA, "Memnite", 1); + // Verify that a room with no name is on playerA's battlefield. + assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); + // Verify that "Felidar Guardian" is on playerA's battlefield. + assertPermanentCount(playerA, "Felidar Guardian", 1); + // Verify that a room with no name is an Enchantment. + assertType(EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), CardType.ENCHANTMENT, true); + // Verify that a room with no name has the Room subtype. + assertSubtype(EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), SubType.ROOM); + } + + @Test + public void testFlickerCanBeUnlockedAgain() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Felidar Guardian"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + // creatures owned by player A + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Black Knight", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + // resolve spell cast + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // unlock and trigger bounce on Memnite + addTarget(playerA, "Memnite"); + // resolve bounce + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Felidar Guardian"); + // resolve spell cast + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // etb and flicker on Bottomless Pool + setChoice(playerA, "Yes"); + addTarget(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // can unlock again + checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}: Unlock the left half.", true); + // unlock again + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}: Unlock the left half."); + addTarget(playerA, "Black Knight"); + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that one "Memnite" has been returned to playerA's hand. + assertHandCount(playerA, "Memnite", 1); + // Verify that one "Black Knight" has been returned to playerA's hand. + assertHandCount(playerA, "Black Knight", 1); + // Verify that "Bottomless Pool" is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPool, 1); + // Verify that "Felidar Guardian" is on playerA's battlefield. + assertPermanentCount(playerA, "Felidar Guardian", 1); + } + + @Test + public void testEerie() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.BATTLEFIELD, playerA, "Erratic Apparition", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + // resolve spell cast + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + setChoice(playerA, "When you unlock"); // x2 triggers + // don't bounce anything + addTarget(playerA, TestPlayer.TARGET_SKIP); + // resolve ability + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // unlock other side + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that bottomlessPoolLockerRoom is on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + // Verify that "Erratic Apparition" is on playerA's battlefield. + assertPermanentCount(playerA, "Erratic Apparition", 1); + // Verify that "Erratic Apparition" has been pumped twice (etb + fully unlock) + assertPowerToughness(playerA, "Erratic Apparition", 3, 5); + } + + @Test + public void testCopyOnStack() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner’s hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "See Double"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + // Copy spell on the stack + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "See Double"); + setModeChoice(playerA, "1"); + addTarget(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 3); + addTarget(playerA, "Memnite"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, "Ornithopter"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that one "Memnite" has been returned to playerA's hand. + assertHandCount(playerA, "Memnite", 1); + // Verify that one "Ornithopter" has been returned to playerA's hand. + assertHandCount(playerA, "Ornithopter", 1); + // Verify that 2 "Bottomless Pool" are on playerA's battlefield. + assertPermanentCount(playerA, bottomlessPool, 2); + } + + @Test + public void testCopyOnBattlefield() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Clever Impersonator"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, "Memnite"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // Copy spell on the battlefield + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + setChoice(playerA, "Yes"); + setChoice(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}: Unlock the left half."); + addTarget(playerA, "Ornithopter"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that one "Memnite" has been returned to playerA's hand (from original + // unlock). + assertHandCount(playerA, "Memnite", 1); + // Verify that "Ornithopter" has been returned to playerA's hand (from clone + // unlock). + assertHandCount(playerA, "Ornithopter", 1); + // Verify that the original "Bottomless Pool" is on playerA's battlefield, and a + // clone. + assertPermanentCount(playerA, bottomlessPool, 2); + } + + @Test + public void testNameMatchOnStack() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + + // Mindreaver + // {U}{U} + // Creature — Human Wizard + // Heroic — Whenever you cast a spell that targets this creature, exile the top + // three cards of target player’s library. + // {U}{U}, Sacrifice this creature: Counter target spell with the same name as a + // card exiled with this creature. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Twiddle"); + addCard(Zone.BATTLEFIELD, playerA, "Mindreaver", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.LIBRARY, playerA, bottomlessPoolLockerRoom, 1); + addCard(Zone.LIBRARY, playerA, "Plains", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Twiddle"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // tap or untap target permanent + addTarget(playerA, "Mindreaver"); + // tap that permanent? + setChoice(playerA, "No"); + // Whenever you cast a spell that targets this creature, exile the top + // three cards of target player’s library. + addTarget(playerA, playerA); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{U}{U}, Sacrifice {this}:"); + addTarget(playerA, bottomlessPool); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + } + + @Test + public void testNameMatchOnFieldFromLocked() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + // + // Opalescence + // {2}{W}{W} + // Enchantment + // Each other non-Aura enchantment is a creature in addition to its other types + // and has base power and base toughness each equal to its mana value. + // + // Glorious Anthem + // {1}{W}{W} + // Enchantment + // Creatures you control get +1/+1. + // + // Cackling Counterpart + // {1}{U}{U} + // Instant + // Create a token that's a copy of target creature you control. + // + // Bile Blight + // {B}{B} + // Instant + // Target creature and all other creatures with the same name as that creature + // get -3/-3 until end of turn. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); + addCard(Zone.HAND, playerA, "Cackling Counterpart"); + addCard(Zone.HAND, playerA, "Bile Blight"); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); + addCard(Zone.BATTLEFIELD, playerA, "Glorious Anthem"); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + + // Cast Bottomless Pool (unlocked left half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Locker Room (unlocked right half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Create a fully locked room using Cackling Counterpart + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); + addTarget(playerA, bottomlessPoolLockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bile Blight targeting the fully locked room + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight"); + addTarget(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand()); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // The fully locked room should be affected by Bile Blight (-3/-3) + // Since it's a 0/0 creature (mana value 0) +1/+1 from anthem, it becomes 1/1, + // then -2/-2 after Bile Blight (dies) + assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 0); + // Token, so nothing should be in grave + assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 0); + + // Other rooms should NOT be affected by Bile Blight since they have different + // names + // Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 + assertPowerToughness(playerA, bottomlessPool, 2, 2); + // Locker Room: 5/5 base + 1/1 from anthem = 6/6 + assertPowerToughness(playerA, lockerRoom, 6, 6); + // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem = 7/7 + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 7, 7); + + // Verify remaining rooms are still on battlefield + assertPermanentCount(playerA, bottomlessPool, 1); + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + } + + @Test + public void testNameMatchOnFieldFromHalf() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + // + // Opalescence + // {2}{W}{W} + // Enchantment + // Each other non-Aura enchantment is a creature in addition to its other types + // and has base power and base toughness each equal to its mana value. + // + // Glorious Anthem + // {1}{W}{W} + // Enchantment + // Creatures you control get +1/+1. + // + // Cackling Counterpart + // {1}{U}{U} + // Instant + // Create a token that's a copy of target creature you control. + // + // Bile Blight + // {B}{B} + // Instant + // Target creature and all other creatures with the same name as that creature + // get -3/-3 until end of turn. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); + addCard(Zone.HAND, playerA, "Cackling Counterpart"); + addCard(Zone.HAND, playerA, "Bile Blight"); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); + addCard(Zone.BATTLEFIELD, playerA, "Glorious Anthem"); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + + // Cast Bottomless Pool (unlocked left half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Locker Room (unlocked right half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Create a fully locked room using Cackling Counterpart + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); + addTarget(playerA, bottomlessPoolLockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bile Blight targeting the half locked room + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight"); + addTarget(playerA, lockerRoom); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // Locker Room and Bottomless Pool // Locker Room should both be affected by + // Bile Blight + // since they share the "Locker Room" name component + + // Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3 + assertPowerToughness(playerA, lockerRoom, 3, 3); + // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile + // Blight = 4/4 + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4); + + // Other rooms should NOT be affected + // Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 (unaffected) + assertPowerToughness(playerA, bottomlessPool, 2, 2); + // Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected) + assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1); + + // Verify all rooms are still on battlefield + assertPermanentCount(playerA, bottomlessPool, 1); + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); + } + + @Test + public void testNameMatchOnFieldFromUnlocked() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + // + // Opalescence + // {2}{W}{W} + // Enchantment + // Each other non-Aura enchantment is a creature in addition to its other types + // and has base power and base toughness each equal to its mana value. + // + // Glorious Anthem + // {1}{W}{W} + // Enchantment + // Creatures you control get +1/+1. + // + // Cackling Counterpart + // {1}{U}{U} + // Instant + // Create a token that's a copy of target creature you control. + // + // Bile Blight + // {B}{B} + // Instant + // Target creature and all other creatures with the same name as that creature + // get -3/-3 until end of turn. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4); + addCard(Zone.HAND, playerA, "Cackling Counterpart"); + addCard(Zone.HAND, playerA, "Bile Blight"); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17); + addCard(Zone.BATTLEFIELD, playerA, "Glorious Anthem"); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + + // Cast Bottomless Pool (unlocked left half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Locker Room (unlocked right half) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bottomless Pool then unlock Locker Room (both halves unlocked) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Create a fully locked room using Cackling Counterpart + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart"); + addTarget(playerA, bottomlessPoolLockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Bile Blight targeting the fully locked room + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight"); + addTarget(playerA, bottomlessPoolLockerRoom); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // All rooms except the fully locked room should be affected by Bile Blight + // since they all share name components with bottomlessPoolLockerRoom + + // Bottomless Pool: 1/1 base + 1/1 from anthem - 3/3 from Bile Blight = -1/-1 + // (dies) + assertPermanentCount(playerA, bottomlessPool, 0); + assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 1); + + // Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3 + assertPowerToughness(playerA, lockerRoom, 3, 3); + + // Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile + // Blight = 4/4 + assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4); + + // Fully locked room should NOT be affected (different name) + // Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected) + assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1); + + // Verify remaining rooms are still on battlefield + assertPermanentCount(playerA, lockerRoom, 1); + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); + } + + @Test + public void testCounterspellThenReanimate() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Counterspell"); + addCard(Zone.HAND, playerA, "Campus Renovation"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + // Target creature for potential bounce (should not be bounced) + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1); + + // Cast Bottomless Pool + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + + // Counter it while on stack + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell"); + addTarget(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Use Campus Renovation to return it from graveyard + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Campus Renovation"); + addTarget(playerA, bottomlessPoolLockerRoom); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Assertions: + // Verify that "Grizzly Bears" is still on playerB's battlefield (not bounced) + assertPermanentCount(playerB, "Grizzly Bears", 1); + // Verify that "Grizzly Bears" is not in playerB's hand + assertHandCount(playerB, "Grizzly Bears", 0); + // Verify that a room with no name is on playerA's battlefield + assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1); + // Verify that the nameless room is an Enchantment + assertType(EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), CardType.ENCHANTMENT, true); + // Verify that the nameless room has the Room subtype + assertSubtype(EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), SubType.ROOM); + // Verify that Campus Renovation is in graveyard + assertGraveyardCount(playerA, "Campus Renovation", 1); + // Verify that Counterspell is in graveyard + assertGraveyardCount(playerA, "Counterspell", 1); + } + + @Test + public void testPithingNeedleActivatedAbility() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + // + // Opalescence + // {2}{W}{W} + // Enchantment + // Each other non-Aura enchantment is a creature in addition to its other types + // and has base power and base toughness each equal to its mana value. + // + // Diviner's Wand + // {3} + // Kindred Artifact — Wizard Equipment + // 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." + // Whenever a Wizard creature enters, you may attach this Equipment to it. + // Equip {3} + // + // Pithing Needle + // {1} + // Artifact + // As Pithing Needle enters, choose a card name. + // Activated abilities of sources with the chosen name can't be activated. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Pithing Needle"); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + addCard(Zone.BATTLEFIELD, playerA, "Diviner's Wand"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 20); + + // Cast Bottomless Pool (unlocked left half only) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Equip Diviner's Wand + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}"); + addTarget(playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Pithing Needle naming the locked side + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle"); + setChoice(playerA, lockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Validate that the room can activate the gained ability + checkPlayableAbility("Room can use Diviner's Wand ability", 1, PhaseStep.PRECOMBAT_MAIN, playerA, + "{4}: Draw a card.", true); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Unlock the other side + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Validate that you can no longer activate the ability + checkPlayableAbility("Room cannot use Diviner's Wand ability after unlock", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "{4}: Draw a card.", false); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Verify the room is now fully unlocked + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + } + + // Test converting one permanent into one room, then another (the room halves + // should STAY UNLOCKED on the appropriate side!) + @Test + public void testUnlockingPermanentMakeCopyOfOtherRoom() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + // + // Surgical Suite {1}{W} + // When you unlock this door, return target creature card with mana value 3 or + // less from your graveyard to the battlefield. + // Hospital Room {3}{W} + // Whenever you attack, put a +1/+1 counter on target attacking creature. + // + // Mirage Mirror {3} + // {3}: Mirage Mirror becomes a copy of target artifact, creature, enchantment, + // or + // land until end of turn. + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.HAND, playerA, "Surgical Suite // Hospital Room"); + addCard(Zone.BATTLEFIELD, playerA, "Mirage Mirror"); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 20); + addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1); + + // Cast Bottomless Pool (unlocked left half only) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Surgical Suite (unlocked left half only) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Surgical Suite"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this} becomes a copy"); + addTarget(playerA, bottomlessPoolLockerRoom); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half."); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this} becomes a copy"); + addTarget(playerA, "Surgical Suite"); + + attack(3, playerA, "Memnite"); + addTarget(playerA, "Memnite"); + setStopAt(3, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + // Verify unlocked Bottomless pool + assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1); + // Verify unlocked Surgical Suite + assertPermanentCount(playerA, "Surgical Suite", 1); + // Verify mirage mirror is Hospital Room + assertPermanentCount(playerA, "Hospital Room", 1); + // Memnite got a buff + assertPowerToughness(playerA, "Memnite", 2, 2); + } + + @Test + public void testSakashimaCopiesRoomCard() { + skipInitShuffling(); + // Bottomless Pool {U} When you unlock this door, return up to one target + // creature to its owner's hand. + // Locker Room {4}{U} Whenever one or more creatures you control deal combat + // damage to a player, draw a card. + + // Sakashima the Impostor {2}{U}{U} + // Legendary Creature — Human Rogue + // You may have Sakashima the Impostor enter the battlefield as a copy of any + // creature on the battlefield, + // except its name is Sakashima the Impostor, it's legendary in addition to its + // other types, + // and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at + // the beginning of the next end step." + String sakashimaTheImpostor = "Sakashima the Impostor"; + + addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom); + addCard(Zone.BATTLEFIELD, playerA, "Island", 10); + addCard(Zone.BATTLEFIELD, playerA, "Opalescence"); + addCard(Zone.HAND, playerA, sakashimaTheImpostor); + + + // Cast Bottomless Pool (unlocked left half only) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + addTarget(playerA, TestPlayer.TARGET_SKIP); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Cast Sakashima copying the room + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sakashimaTheImpostor); + setChoice(playerA, "Yes"); // Choose to copy + setChoice(playerA, bottomlessPool); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + // Verify Sakashima dies to state-based actions + // copies room and because sakashima has no unlocked designations, its mana value is 0 + // opalescence makes it a 0/0 and it dies + assertPermanentCount(playerA, sakashimaTheImpostor, 0); + assertGraveyardCount(playerA, sakashimaTheImpostor, 1); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/SacredBoonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/SacredBoonTest.java new file mode 100644 index 00000000000..4e384225b0b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/prevent/SacredBoonTest.java @@ -0,0 +1,62 @@ + +package org.mage.test.cards.replacement.prevent; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author notgreat + */ + +public class SacredBoonTest extends CardTestPlayerBase { + + @Test + public void testSacredBoonBigDamage() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, "Sacred Boon"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.HAND, playerB, "Bombard"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacred Boon", "Silvercoat Lion"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Bombard", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertDamageReceived(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 5); + } + + @Test + public void testSacredBoonSmallDamage() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, "Sacred Boon"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + addCard(Zone.HAND, playerB, "Scattershot"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacred Boon", "Silvercoat Lion"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Scattershot", "Silvercoat Lion"); + setChoice(playerB, false); // don't change scattershot targets + setChoice(playerA, "At the"); // stack triggers - technically incorrect, should be a single trigger + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertDamageReceived(playerA, "Silvercoat Lion", 0); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 4); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java index 03327878361..858946e2128 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmm/BattleAtTheHelvaultTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.cmm; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -19,7 +18,6 @@ public class BattleAtTheHelvaultTest extends CardTestPlayerBase { */ private static final String battle = "Battle at the Helvault"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, battle, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java index 82fb895ccce..527cba0941b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/SummonIxionTest.java @@ -3,7 +3,6 @@ package org.mage.test.cards.single.fic; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -23,7 +22,6 @@ public class SummonIxionTest extends CardTestPlayerBase { */ private static final String ixion = "Summon: Ixion"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, ixion, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java index dcc3b7670fd..94bd1b50a90 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khc/EtherealValkyrieTest.java @@ -36,6 +36,8 @@ public class EtherealValkyrieTest extends CardTestPlayerBase { private static final String alloyMyr = "Alloy Myr"; // Land private static final String exoticOrchard = "Exotic Orchard"; + // {U} Creature-Planeswalker TDFC + private static final String tamiyo = "Tamiyo, Inquisitive Student"; /** * Test that a regular card is playable. @@ -202,4 +204,27 @@ public class EtherealValkyrieTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); } + + /** + * Test a TDFC, which should be castable. + */ + @Test + public void testTransformingDoubleFacedCard() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, etherealValkyrie); + addCard(Zone.HAND, playerA, tamiyo); + + setStrictChooseMode(true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, etherealValkyrie); + addTarget(playerA, tamiyo); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {U}"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + + execute(); + assertPermanentCount(playerA, tamiyo, 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/AltarOfTheWretchedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/AltarOfTheWretchedTest.java new file mode 100644 index 00000000000..b829ca93a16 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/AltarOfTheWretchedTest.java @@ -0,0 +1,72 @@ +package org.mage.test.cards.single.lcc; + +import mage.abilities.Ability; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author Jmlundeen + */ +public class AltarOfTheWretchedTest extends CardTestPlayerBase { + + /* + Altar of the Wretched + {2}{B} + Artifact + When Altar of the Wretched enters the battlefield, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creature's power. + Craft with one or more creatures {2}{B}{B} + {2}{B}: Return Altar of the Wretched from your graveyard to your hand. + + Wretched Bonemass + Color Indicator: Black + Creature — Skeleton Horror + Wretched Bonemass’s power and toughness are each equal to the total power of the exiled cards used to craft it. + This creature has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance. + 0/0 + */ + private static final String altarOfTheWretched = "Altar of the Wretched"; + private static final String wretchedBoneMass = "Wretched Bonemass"; + + /* + Angel of Invention + {3}{W}{W} + Creature - Angel + Flying, vigilance, lifelink + Fabricate 2 + Other creatures you control get +1/+1. + 2/1 + */ + private static final String angelOfInvention = "Angel of Invention"; + + + @Test + public void testAltarOfTheWretched() { + addCard(Zone.BATTLEFIELD, playerA, altarOfTheWretched); + addCard(Zone.BATTLEFIELD, playerA, angelOfInvention); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft with one or more"); + addTarget(playerA, angelOfInvention); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPowerToughness(playerA, wretchedBoneMass, 2, 2); + assertExileCount(playerA, angelOfInvention, 1); + List abilities = new ArrayList<>(); + abilities.add(FlyingAbility.getInstance()); + abilities.add(VigilanceAbility.getInstance()); + abilities.add(LifelinkAbility.getInstance()); + assertAbilities(playerA, wretchedBoneMass, abilities); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/EyeOfOjerTaqTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/EyeOfOjerTaqTest.java new file mode 100644 index 00000000000..2053ff2367f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/EyeOfOjerTaqTest.java @@ -0,0 +1,86 @@ +package org.mage.test.cards.single.lcc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Jmlundeen + */ +public class EyeOfOjerTaqTest extends CardTestPlayerBase { + + /* + Eye of Ojer Taq + {3} + Artifact + {T}: Add one mana of any color. + Craft with two that share a card type {6} + + Apex Observatory + Artifact + Apex Observatory enters the battlefield tapped. As it enters, choose a card type shared among two exiled cards used to craft it. + {T}: The next spell you cast this turn of the chosen type can be cast without paying its mana cost. + */ + private static final String eyeOfOjerTaq = "Eye of Ojer Taq"; + private static final String apexObservatory = "Apex Observatory"; + + /* + Lightning Bolt + {R} + Instant + Lightning Bolt deals 3 damage to any target. + */ + private static final String lightningBolt = "Lightning Bolt"; + + /* + Ponder + {U} + Sorcery + Look at the top three cards of your library, then put them back in any order. You may shuffle your library. + Draw a card. + */ + private static final String ponder = "Ponder"; + + /* + Shock + {R} + Instant + Shock deals 2 damage to any target. + */ + private static final String shock = "Shock"; + + @Test + public void testEyeOfOjerTaq() { + addCard(Zone.BATTLEFIELD, playerA, eyeOfOjerTaq); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.GRAVEYARD, playerA, lightningBolt); + addCard(Zone.GRAVEYARD, playerA, shock); + addCard(Zone.HAND, playerA, shock, 2); + addCard(Zone.HAND, playerA, ponder); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft with two that share a card type"); + addTarget(playerA, lightningBolt + "^" + shock); + setChoice(playerA, "Instant"); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: The next spell"); + waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN, playerA); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, shock, playerB); // should be able to cast for free + setChoice(playerA, "Cast without paying"); + checkPlayableAbility("Can't cast second shock", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Shock", false); + + checkPlayableAbility("Can't cast ponder", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Ponder", false); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 20 - 2); // took 2 damage from shock + assertExileCount(playerA, lightningBolt, 1); + assertExileCount(playerA, shock, 1); + assertGraveyardCount(playerA, shock, 1); + assertPermanentCount(playerA, apexObservatory, 1); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/SaheelisLatticeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/SaheelisLatticeTest.java new file mode 100644 index 00000000000..010a6ef18a6 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/SaheelisLatticeTest.java @@ -0,0 +1,67 @@ +package org.mage.test.cards.single.lci; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Jmlundeen + */ +public class SaheelisLatticeTest extends CardTestPlayerBase { + + /* + Saheeli's Lattice + {1}{R} + Artifact + When Saheeli's Lattice enters the battlefield, you may discard a card. If you do, draw two cards. + Craft with one or more Dinosaurs {4}{R} + Mastercraft Raptor + Artifact Creature - Dinosaur + Mastercraft Raptor's power is equal to the total power of the exiled cards used to craft it. + 0/4 + */ + private static final String saheelisLattice = "Saheeli's Lattice"; + private static final String mastercraftRaptor = "Mastercraft Raptor"; + + /* + Balamb T-Rexaur + {4}{G}{G} + Creature - Dinosaur + Trample + When this creature enters, you gain 3 life. + Forestcycling {2} + 6/6 + */ + private static final String balambTRexaur = "Balamb T-Rexaur"; + + /* + Zetalpa, Primal Dawn + {6}{W}{W} + Legendary Creature - Elder Dinosaur + Flying, double strike, vigilance, trample, indestructible + 4/8 + */ + private static final String zetalpaPrimalDawn = "Zetalpa, Primal Dawn"; + + @Test + public void testSaheelisLattice() { + addCard(Zone.BATTLEFIELD, playerA, saheelisLattice); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.GRAVEYARD, playerA, balambTRexaur); + addCard(Zone.GRAVEYARD, playerA, zetalpaPrimalDawn); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft with one"); + addTarget(playerA, balambTRexaur + "^" + zetalpaPrimalDawn); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, mastercraftRaptor, 1); + assertPowerToughness(playerA, mastercraftRaptor, 6 + 4, 4); + assertExileCount(playerA, balambTRexaur, 1); + assertExileCount(playerA, zetalpaPrimalDawn, 1); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheEnigmaJewelTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheEnigmaJewelTest.java new file mode 100644 index 00000000000..feb38725cfd --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lci/TheEnigmaJewelTest.java @@ -0,0 +1,93 @@ +package org.mage.test.cards.single.lci; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.permanent.Permanent; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * + * @author Jmlundeen + */ +public class TheEnigmaJewelTest extends CardTestPlayerBase { + + /* + The Enigma Jewel + {U} + Legendary Artifact + The Enigma Jewel enters the battlefield tapped. + {T}: Add {C}{C}. Spend this mana only to activate abilities. + Craft with four or more nonlands with activated abilities {8}{U} + Locus of Enlightenment + Legendary Artifact + Locus of Enlightenment has each activated ability of the exiled cards used to craft it. You may activate each of those abilities only once each turn. + Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy. + */ + private static final String theEnigmaJewel = "The Enigma Jewel"; + private static final String locusOfEnlightenment = "Locus of Enlightenment"; + + /* + Scavenging Ooze + {1}{G} + Creature - Ooze + {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. + 2/2 + */ + private static final String scavengingOoze = "Scavenging Ooze"; + + /* + Aetherflame Wall + {1}{R} + Creature - Wall + Defender + Ætherflame Wall can block creatures with shadow as though they didn't have shadow. + {R}: Ætherflame Wall gets +1/+0 until end of turn. + 0/4 + */ + private static final String aetherflameWall = "Aetherflame Wall"; + + /* + Ancient Silverback + {4}{G}{G} + Creature - Ape + {G}: Regenerate Ancient Silverback. (The next time this creature would be destroyed this turn, it isn't. Instead tap it, remove all damage from it, and remove it from combat.) + 6/5 + */ + private static final String ancientSilverback = "Ancient Silverback"; + + /* + Ancient Hellkite + {4}{R}{R}{R} + Creature - Dragon + Flying + {R}: Ancient Hellkite deals 1 damage to target creature defending player controls. Activate this ability only if Ancient Hellkite is attacking. + 6/6 + */ + private static final String ancientHellkite = "Ancient Hellkite"; + + @Test + public void testTheEnigmaJewelCraft() { + addCard(Zone.BATTLEFIELD, playerA, theEnigmaJewel); + addCard(Zone.BATTLEFIELD, playerA, scavengingOoze); + addCard(Zone.BATTLEFIELD, playerA, aetherflameWall); + addCard(Zone.BATTLEFIELD, playerA, ancientSilverback); + addCard(Zone.BATTLEFIELD, playerA, ancientHellkite); + addCard(Zone.BATTLEFIELD, playerA, "Taiga", 10); + addCard(Zone.BATTLEFIELD, playerA, "Island"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Craft with"); + addTarget(playerA, scavengingOoze + "^" + aetherflameWall + "^" + ancientSilverback + "^" + ancientHellkite); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + Permanent permanent = getPermanent(locusOfEnlightenment, playerA); + assertNotNull(permanent); + assertEquals(4, permanent.getAbilities(currentGame).getActivatedAbilities(Zone.BATTLEFIELD).size()); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mbs/KnowledgePoolTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mbs/KnowledgePoolTest.java new file mode 100644 index 00000000000..746e487577a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mbs/KnowledgePoolTest.java @@ -0,0 +1,61 @@ +package org.mage.test.cards.single.mbs; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Jmlundeen + */ +public class KnowledgePoolTest extends CardTestPlayerBase { + + /* + Knowledge Pool + {6} + Artifact + Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of their library. + 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. + */ + private static final String knowledgePool = "Knowledge Pool"; + + /* + Lightning Bolt + {R} + Instant + Lightning Bolt deals 3 damage to any target. + */ + private static final String lightningBolt = "Lightning Bolt"; + + /* + Shock + {R} + Instant + Shock deals 2 damage to any target. + */ + private static final String shock = "Shock"; + + @Test + public void testKnowledgePool() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain"); + addCard(Zone.BATTLEFIELD, playerA, knowledgePool); + addCard(Zone.HAND, playerA, lightningBolt); + addCard(Zone.HAND, playerB, shock); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lightningBolt, playerB); + setChoice(playerA, false); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, shock, playerA); + setChoice(playerB, true); + setChoice(playerB, lightningBolt); + addTarget(playerB, playerA); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertLife(playerA, 20 - 3); // shock exiled, bolt cast from knowledge pool + assertLife(playerB, 20); // bolt exiled, no card to cast from knowledge pool + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java index 16b0a3f9ae9..b5ddd69b912 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/pip/Vault13DwellersJourneyTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.pip; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -21,7 +20,6 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase { */ private static final String vault = "Vault 13: Dweller's Journey"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_ReturnOne() { addCard(Zone.HAND, playerA, vault, 1); @@ -49,7 +47,6 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Memnite", 1); assertLife(playerA, 20 + 2); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_Return() { addCard(Zone.HAND, playerA, vault, 1); @@ -81,7 +78,6 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase { assertLife(playerA, 20 + 2); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_NoReturn() { addCard(Zone.HAND, playerA, vault, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/shm/GlamerSpinnersTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/shm/GlamerSpinnersTest.java new file mode 100644 index 00000000000..b1277b678a2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/shm/GlamerSpinnersTest.java @@ -0,0 +1,74 @@ +package org.mage.test.cards.single.shm; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class GlamerSpinnersTest extends CardTestPlayerBase { + + /* + Glamer Spinners + {4}{WU} + Creature - Faerie Wizard + Flash + Flying + When Glamer Spinners enters the battlefield, attach all Auras enchanting target permanent to another permanent with the same controller. + 2/4 + */ + private static final String glamerSpinners = "Glamer Spinners"; + + /* + Feral Invocation + {2}{G} + Enchantment - Aura + Flash (You may cast this spell any time you could cast an instant.) + Enchant creature + Enchanted creature gets +2/+2. + */ + private static final String feralInvocation = "Feral Invocation"; + + /* + Memnite + {0} + Artifact Creature - Construct + 1/1 + */ + private static final String memnite = "Memnite"; + + /* + Kraken Hatchling + {U} + Creature - Kraken + 0/4 + */ + private static final String krakenHatchling = "Kraken Hatchling"; + + @Test + public void testGlamerSpinners() { + addCard(Zone.HAND, playerA, glamerSpinners); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.HAND, playerB, feralInvocation); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 3); + addCard(Zone.BATTLEFIELD, playerB, memnite); + addCard(Zone.BATTLEFIELD, playerB, krakenHatchling); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, feralInvocation, memnite); + checkPT("enchanted", 1, PhaseStep.BEGIN_COMBAT, playerB, memnite, 3, 3); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, glamerSpinners); + addTarget(playerA, memnite); + setChoice(playerA, krakenHatchling); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, glamerSpinners, 1); + assertPowerToughness(playerB, memnite, 1, 1); + assertPowerToughness(playerB, krakenHatchling, 2, 6); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ElectroAssaultingBatteryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ElectroAssaultingBatteryTest.java index a8a039f54da..450d5d16cd1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ElectroAssaultingBatteryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ElectroAssaultingBatteryTest.java @@ -1,8 +1,10 @@ package org.mage.test.cards.single.spm; +import mage.constants.ManaType; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** @@ -39,6 +41,16 @@ public class ElectroAssaultingBatteryTest extends CardTestPlayerBase { */ private static final String lightningBolt = "Lightning Bolt"; + /* + Final Showdown + {W} + Instant + Spree + + {1} -- All creatures lose all abilities until end of turn. + + {1} -- Choose a creature you control. It gains indestructible until end of turn. + + {3}{W}{W} -- Destroy all creatures. + */ + private static final String finalShowdown = "Final Showdown"; @Test public void testElectroAssaultingBattery() { @@ -62,4 +74,34 @@ public class ElectroAssaultingBatteryTest extends CardTestPlayerBase { assertLife(playerB, 20 - 4); } + + @Test + public void testElectroAssaultingBatteryFinalShowdown() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, electroAssaultingBattery); + addCard(Zone.BATTLEFIELD, playerA, "Mountain"); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 7); + addCard(Zone.HAND, playerB, finalShowdown); + addCard(Zone.HAND, playerA, lightningBolt); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lightningBolt, playerB); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, finalShowdown); + setModeChoice(playerB, "1"); + setModeChoice(playerB, "3"); + setModeChoice(playerB, TestPlayer.MODE_SKIP); + + checkManaPool("Should have 1 red mana", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "R", 1); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, lightningBolt, 1); + assertGraveyardCount(playerB, finalShowdown, 1); + assertGraveyardCount(playerA, electroAssaultingBattery, 1); + + assertManaPool(playerA, ManaType.RED, 0); // Electro's ability is gone + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java index 223f35b68c7..b6cf20ff645 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/GwenStacyTest.java @@ -3,7 +3,6 @@ package org.mage.test.cards.single.spm; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -33,7 +32,6 @@ public class GwenStacyTest extends CardTestPlayerBase { private static final String ghostSpider = "Ghost-Spider"; @Test - @Ignore("Enable after transform mdfc rework") public void testGhostSpider() { setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/OscorpIndustriesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/OscorpIndustriesTest.java index 364cc480059..4e3f23468fa 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/OscorpIndustriesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/OscorpIndustriesTest.java @@ -41,7 +41,7 @@ public class OscorpIndustriesTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw"); setChoice(playerA, oscorpIndustries); - playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, oscorpIndustries + " with Mayhem"); + playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, oscorpIndustries); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -49,4 +49,56 @@ public class OscorpIndustriesTest extends CardTestPlayerBase { assertLife(playerA, 20 - 2); assertPermanentCount(playerA, oscorpIndustries, 1); } + + @Test + public void testOscorpIndustriesNoMayhem() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, oscorpIndustries); + addCard(Zone.BATTLEFIELD, playerA, thoughtCourier); + + playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, oscorpIndustries); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertPermanentCount(playerA, oscorpIndustries, 1); + } + + @Test + public void testCantPlayWithoutDiscard() { + setStrictChooseMode(true); + + addCard(Zone.GRAVEYARD, playerA, oscorpIndustries); + + checkPlayableAbility("Can't play without discard", 1, PhaseStep.PRECOMBAT_MAIN, playerA, + "Play " + oscorpIndustries, false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertPermanentCount(playerA, oscorpIndustries, 0); + } + + @Test + public void testOscorpIndustriesNextTurn() { + setStrictChooseMode(true); + + addCard(Zone.HAND, playerA, oscorpIndustries); + addCard(Zone.BATTLEFIELD, playerA, thoughtCourier); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw"); + setChoice(playerA, oscorpIndustries); + + checkPlayableAbility("Can't play without discard", 3, PhaseStep.PRECOMBAT_MAIN, playerA, + "Play " + oscorpIndustries, false); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertPermanentCount(playerA, oscorpIndustries, 0); + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java index 38eeace4a37..38fe6fa6e9f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/PeterParkerTest.java @@ -7,7 +7,6 @@ import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -18,19 +17,20 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class PeterParkerTest extends CardTestPlayerBase { /* - Peter Parker - {1}{W} - Legendary Creature - Human Scientist Hero - When Peter Parker enters, create a 2/1 green Spider creature token with reach. - {1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery. - Amazing Spider-Man - {1}{G}{W}{U} - Legendary Creature - Spider Human Hero - Vigilance, reach - Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}. - 4/4 - */ + Peter Parker + {1}{W} + Legendary Creature - Human Scientist Hero + When Peter Parker enters, create a 2/1 green Spider creature token with reach. + {1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery. + Amazing Spider-Man + {1}{G}{W}{U} + Legendary Creature - Spider Human Hero + Vigilance, reach + Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}. + 4/4 + */ private static final String peterParker = "Peter Parker"; + public static final String amazingSpiderMan = "Amazing Spider-Man"; /* @@ -73,8 +73,16 @@ public class PeterParkerTest extends CardTestPlayerBase { */ private static final String balduvianBears = "Balduvian Bears"; + /* + Unsummon + {U} + Instant + Return target creature to its owner's hand. + */ + private static final String unsummon = "Unsummon"; + + @Test - @Ignore("Enable after MDFC rework") public void testAmazingSpiderMan() { setStrictChooseMode(true); @@ -91,7 +99,7 @@ public class PeterParkerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Amazing Spider-Man", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); @@ -112,4 +120,131 @@ public class PeterParkerTest extends CardTestPlayerBase { execute(); } + + @Test + public void testTransform() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, adelbertSteiner + " with Web-slinging"); + setChoice(playerA, balduvianBears); // return to hand + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 1); + assertPermanentCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 0); + assertHandCount(playerA, balduvianBears, 1); + } + + /** + * test that MDFC doesn't have static ability from one side after transforming + */ + @Test + public void testTransformLosesWebSlinging() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + addCustomEffect_TargetTransform(playerA); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform"); // transform to Spider-Man + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", true); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 0); + assertPermanentCount(playerA, peterParker, 1); + assertHandCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 1); + } + + /** + * test showing if a transformed MDFC gets re-cast, it won't trigger effects from the other face + */ + @Test + public void testTransformCastSecondSideDoesntTriggerFront() { + setStrictChooseMode(true); + + addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility( + new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")), + new ManaCostsImpl<>("") + )); + addCustomEffect_TargetTransform(playerA); + + addCard(Zone.HAND, playerA, peterParker); + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8); + addCard(Zone.BATTLEFIELD, playerA, balduvianBears); + addCard(Zone.HAND, playerA, adelbertSteiner); + addCard(Zone.HAND, playerA, unsummon); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true); + + checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", true); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN, + playerA, "Cast " + adelbertSteiner + " with Web-slinging", false); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, unsummon, peterParker, true); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, amazingSpiderMan); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, amazingSpiderMan, 1); + assertPermanentCount(playerA, peterParker, 0); + assertHandCount(playerA, adelbertSteiner, 1); + assertPermanentCount(playerA, balduvianBears, 1); + assertPermanentCount(playerA, "Spider Token", 0); + currentGame.getState().getTriggers().forEach( + (key, value) -> logger.info(key + " - " + value) + ); + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java index 50312827c11..07ff6ec1e9d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/spm/ShadowOfTheGoblinTest.java @@ -61,7 +61,7 @@ public class ShadowOfTheGoblinTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Mountain"); addCard(Zone.HAND, playerA, partyThrasher); - setChoice(playerA, false); // shadow trigger + setChoice(playerA, "Mountain"); // shadow trigger waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); @@ -120,4 +120,4 @@ public class ShadowOfTheGoblinTest extends CardTestPlayerBase { assertLife(playerB, 20 - 1 - 1); // land + spell from library } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java new file mode 100644 index 00000000000..216e8289557 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/unf/EmbiggenTest.java @@ -0,0 +1,50 @@ +package org.mage.test.cards.single.unf; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class EmbiggenTest extends CardTestPlayerBase { + + private static final String roar = "Relic's Roar"; + private static final String embiggen = "Embiggen"; + private static final String agent = "Blighted Agent"; + + @Test + public void testRoarFirst() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 2); + addCard(Zone.BATTLEFIELD, playerA, agent); + addCard(Zone.HAND, playerA, roar); + addCard(Zone.HAND, playerA, embiggen); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, roar, agent, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, embiggen, agent, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, agent, 4 + 4 + 2, 3 + 4 + 2); + } + + @Test + public void testEmbiggenFirst() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 2); + addCard(Zone.BATTLEFIELD, playerA, agent); + addCard(Zone.HAND, playerA, roar); + addCard(Zone.HAND, playerA, embiggen); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, embiggen, agent, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, roar, agent, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, agent, 4 + 3 + 1, 3 + 3 + 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java index bd0c49f72d1..97d1072d424 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/DayOfTheMoonTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.who; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -18,7 +17,6 @@ public class DayOfTheMoonTest extends CardTestPlayerBase { */ private static final String day = "Day of the Moon"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, day, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java index 7bddf646de1..8f5d72293c6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TheWarGamesTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.who; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -20,7 +19,6 @@ public class TheWarGamesTest extends CardTestPlayerBase { */ private static final String war = "The War Games"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_NoExile() { addCard(Zone.HAND, playerA, war, 1); @@ -63,7 +61,6 @@ public class TheWarGamesTest extends CardTestPlayerBase { assertLife(playerB, 20 - 6 - 9); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay_Exile() { addCard(Zone.HAND, playerA, war, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java index 09ae8e86c72..7653a1e1a33 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/who/TrialOfATimeLordTest.java @@ -2,7 +2,6 @@ package org.mage.test.cards.single.who; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -20,7 +19,6 @@ public class TrialOfATimeLordTest extends CardTestPlayerBase { */ private static final String trial = "Trial of a Time Lord"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, trial, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java index e7b9d197590..8ff3950a316 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/ThePrincessTakesFlightTest.java @@ -3,7 +3,6 @@ package org.mage.test.cards.single.woe; import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -21,7 +20,6 @@ public class ThePrincessTakesFlightTest extends CardTestPlayerBase { */ private static final String flight = "The Princess Takes Flight"; - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void test_SimplePlay() { addCard(Zone.HAND, playerA, flight, 1); @@ -54,7 +52,6 @@ public class ThePrincessTakesFlightTest extends CardTestPlayerBase { assertExileCount(playerB, "Memnite", 0); assertPermanentCount(playerB, "Memnite", 1); } - @Ignore // TODO: goal of #11619 is to fix this nicely @Test public void testFlicker() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); @@ -82,4 +79,73 @@ public class ThePrincessTakesFlightTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Memnite", 1); assertGraveyardCount(playerA, flight, 1); } + + @Test + public void test_TokenCopy() { + addCard(Zone.HAND, playerA, flight, 1); + addCard(Zone.HAND, playerA, "Swords to Plowshares", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Ondu Spiritdancer", 1); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, flight); + setChoice(playerA, "I - "); + addTarget(playerA, "Memnite"); + setChoice(playerA, true); + addTarget(playerA, "Grizzly Bears"); + + checkExileCount("after I, exiled Memnite", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Memnite", 1); + checkExileCount("after I, exiled Grizzly Bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Grizzly Bears", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Swords to Plowshares", "Ondu Spiritdancer"); + + // turn 3 + setChoice(playerA, "II - "); + // No targets available + + // turn 5 + setChoice(playerA, "III - "); + setStrictChooseMode(true); + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertExileCount(playerA, "Grizzly Bears", 0); + assertExileCount(playerB, "Memnite", 0); + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerB, "Memnite", 1); + } + @Test + public void test_SpellCopy() { + addCard(Zone.HAND, playerA, flight, 1); + addCard(Zone.HAND, playerA, "Swords to Plowshares", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "The Sixth Doctor", 1); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, flight); + addTarget(playerA, "Memnite"); + addTarget(playerA, "Grizzly Bears"); + + checkExileCount("after I, exiled Memnite", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Memnite", 1); + checkExileCount("after I, exiled Grizzly Bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Grizzly Bears", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Swords to Plowshares", "The Sixth Doctor"); + + // turn 3 + setChoice(playerA, "II - "); + // No targets available + + // turn 5 + setChoice(playerA, "III - "); + setStrictChooseMode(true); + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertExileCount(playerA, "Grizzly Bears", 0); + assertExileCount(playerB, "Memnite", 0); + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerB, "Memnite", 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 2fc31b9d548..6f34ecedda6 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 @@ -213,14 +213,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Tangled Vale"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 1, 1, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Vale"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 2, 2, 4)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -244,14 +242,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Riverglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc pre disfigure", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 1, 2, 1)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Riverglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc post disfigure", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 4, 2)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -275,14 +271,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Lavaglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 1, 1, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 2, 2, 2)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Lavaglide Pathway"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 2, 4)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -335,14 +329,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -403,25 +395,25 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tangled Florahedron"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron"); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("2: check zcc card", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5)); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tangled Florahedron"); waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("3: check zcc", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 4, 7, 4)); + (String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 7, 7, 7)); waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disfigure", "Tangled Florahedron", true); - // TODO: investigate why MDFC zcc moves separatedly. + runCode("4: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, - (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 9, 5)); + (String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 9, 9, 9)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -458,20 +450,19 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { runCode("3: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, (String info, Player player, Game game) -> checkZCCNormalPermanent(info, player, game, "Carrion Feeder", 5, 5)); castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Coat with Venom", "Carrion Feeder", true); - runCode("4: check graveyard zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, - (String info, Player player, Game game) -> checkZCCCardInGraveyard(info, player, game, "Carrion Feeder", 6)); + runCode("4: check hand zcc", 1, PhaseStep.BEGIN_COMBAT, playerA, + (String info, Player player, Game game) -> checkZCCNormalCardInHand(info, player, game, "Carrion Feeder", 7)); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); - // Vigor tries to return the Carrion Feeder card with zcc 4, so 6 doesn't return. assertGraveyardCount(playerA, "Disfigure", 1); assertGraveyardCount(playerA, "Demonic Vigor", 1); assertGraveyardCount(playerA, "Makeshift Mannequin", 1); - assertGraveyardCount(playerA, "Carrion Feeder", 1); + assertGraveyardCount(playerA, "Carrion Feeder", 0); assertPermanentCount(playerA, "Carrion Feeder", 0); - assertHandCount(playerA, "Carrion Feeder", 0); + assertHandCount(playerA, "Carrion Feeder", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiLifelinkTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiLifelinkTriggerTest.java new file mode 100644 index 00000000000..35b642b209c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiLifelinkTriggerTest.java @@ -0,0 +1,191 @@ +package org.mage.test.cards.triggers.damage; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class DamageMultiLifelinkTriggerTest extends CardTestPlayerBase { + + private static final String hatchling = "Kraken Hatchling"; // 0/4 + private static final String wishcoin = "Wishcoin Crab"; // 2/5 + + private static final String devil = "Forge Devil"; // 1/1 + // ETB 1 dmg to any target and 1 dmg to you + private static final String embermage = "Reckless Embermage"; // 2/2 + // 1R: 1 dmg to any target and 1 dmg to itself + + private static final String arc = "Arc Trail"; + // Arc Trail deals 2 damage to any target and 1 damage to another target. + private static final String cone = "Cone of Flame"; + // Cone of Flame deals 1 damage to any target, 2 damage to another target, and 3 damage to a third target. + private static final String chaar = "Char"; + // Char deals 4 damage to any target and 2 damage to you. + private static final String outrage = "Chandra's Outrage"; + // Chandra's Outrage deals 4 damage to target creature and 2 damage to that creature's controller. + private static final String fury = "Chandra's Fury"; + // Chandra's Fury deals 4 damage to target player or planeswalker + // and 1 damage to each creature that player or that planeswalker's controller controls. + + private static final String whip = "Whip of Erebos"; + // Creatures you control have lifelink. + private static final String firesong = "Firesong and Sunspeaker"; + // Red instant and sorcery spells you control have lifelink. + private static final String pridemate = "Ajani's Pridemate"; // 2/2 + // Whenever you gain life, put a +1/+1 counter on this creature. + + private void setupBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, whip); + addCard(Zone.BATTLEFIELD, playerA, firesong); + addCard(Zone.BATTLEFIELD, playerA, pridemate); + addCard(Zone.BATTLEFIELD, playerA, hatchling); + addCard(Zone.BATTLEFIELD, playerB, wishcoin); + } + + @Test + @Ignore + public void testCreatureDamageTargetAndYou() { + setupBattlefield(); + addCard(Zone.HAND, playerA, devil); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, devil); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 - 1 + 2); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testCreatureDamageTargetAndSelf() { + setupBattlefield(); + addCard(Zone.BATTLEFIELD, playerA, embermage); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{R}: "); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 2); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 1); + assertDamageReceived(playerB, embermage, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testSpellDamageTargetAndTarget() { + setupBattlefield(); + addCard(Zone.HAND, playerA, arc); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, arc); + addTarget(playerA, wishcoin); + addTarget(playerA, hatchling); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 3); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 2); + assertDamageReceived(playerA, hatchling, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testSpellDamageThreeTargets() { + setupBattlefield(); + addCard(Zone.HAND, playerA, cone); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cone); + addTarget(playerA, wishcoin); + addTarget(playerA, hatchling); + addTarget(playerA, firesong); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 6); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 3); + assertDamageReceived(playerA, hatchling, 2); + assertDamageReceived(playerA, firesong, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testSpellDamageTargetAndYou() { + setupBattlefield(); + addCard(Zone.HAND, playerA, chaar); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, chaar); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 - 2 + 6); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 4); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testSpellDamageTargetAndController() { + setupBattlefield(); + addCard(Zone.HAND, playerA, outrage); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, outrage); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 6); + assertLife(playerB, 20 - 2); + assertDamageReceived(playerB, wishcoin, 4); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + @Ignore + public void testSpellDamagePlayerAndControlled() { + setupBattlefield(); + addCard(Zone.HAND, playerA, fury); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fury); + addTarget(playerA, playerB); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 5); + assertLife(playerB, 20 - 4); + assertDamageReceived(playerB, wishcoin, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiTriggerTest.java new file mode 100644 index 00000000000..ced360b10bf --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/damage/DamageMultiTriggerTest.java @@ -0,0 +1,188 @@ +package org.mage.test.cards.triggers.damage; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class DamageMultiTriggerTest extends CardTestPlayerBase { + + private static final String hatchling = "Kraken Hatchling"; // 0/4 + private static final String wishcoin = "Wishcoin Crab"; // 2/5 + + private static final String brothers = "Brothers of Fire"; // 2/2 + // 1RR: 1 dmg to any target and 1 dmg to you + private static final String embermage = "Reckless Embermage"; // 2/2 + // 1R: 1 dmg to any target and 1 dmg to itself + + private static final String arc = "Arc Trail"; + // Arc Trail deals 2 damage to any target and 1 damage to another target. + private static final String cone = "Cone of Flame"; + // Cone of Flame deals 1 damage to any target, 2 damage to another target, and 3 damage to a third target. + private static final String chaar = "Char"; + // Char deals 4 damage to any target and 2 damage to you. + private static final String outrage = "Chandra's Outrage"; + // Chandra's Outrage deals 4 damage to target creature and 2 damage to that creature's controller. + private static final String fury = "Chandra's Fury"; + // Chandra's Fury deals 4 damage to target player or planeswalker + // and 1 damage to each creature that player or that planeswalker's controller controls. + + private static final String tamanoa = "Tamanoa"; // 2/4 + // Whenever a noncreature source you control deals damage, you gain that much life. + private static final String spiritLink = "Spirit Link"; // 2/2 + // Whenever enchanted creature deals damage, you gain that much life. + private static final String pridemate = "Ajani's Pridemate"; // 2/2 + // Whenever you gain life, put a +1/+1 counter on this creature. + + private void setupBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, "Plateau", 5); + addCard(Zone.BATTLEFIELD, playerA, tamanoa); + addCard(Zone.HAND, playerA, spiritLink); + addCard(Zone.BATTLEFIELD, playerA, pridemate); + addCard(Zone.BATTLEFIELD, playerA, hatchling); + addCard(Zone.BATTLEFIELD, playerB, wishcoin); + } + + @Test + public void testCreatureDamageTargetAndYou() { + setupBattlefield(); + addCard(Zone.BATTLEFIELD, playerA, brothers); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, spiritLink, brothers); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{R}{R}: "); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 - 1 + 2); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + public void testCreatureDamageTargetAndSelf() { + setupBattlefield(); + addCard(Zone.BATTLEFIELD, playerA, embermage); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, spiritLink, embermage); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{R}: "); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 2); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 1); + assertDamageReceived(playerA, embermage, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + public void testSpellDamageTargetAndTarget() { + setupBattlefield(); + addCard(Zone.HAND, playerA, arc); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, arc); + addTarget(playerA, wishcoin); + addTarget(playerA, hatchling); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 3); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 2); + assertDamageReceived(playerA, hatchling, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + public void testSpellDamageThreeTargets() { + setupBattlefield(); + addCard(Zone.HAND, playerA, cone); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cone); + addTarget(playerA, wishcoin); + addTarget(playerA, hatchling); + addTarget(playerA, tamanoa); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 6); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 1); + assertDamageReceived(playerA, hatchling, 2); + assertDamageReceived(playerA, tamanoa, 3); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + public void testSpellDamageTargetAndYou() { + setupBattlefield(); + addCard(Zone.HAND, playerA, chaar); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, chaar); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 - 2 + 6); + assertLife(playerB, 20); + assertDamageReceived(playerB, wishcoin, 4); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + @Test + public void testSpellDamageTargetAndController() { + setupBattlefield(); + addCard(Zone.HAND, playerA, outrage); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, outrage); + addTarget(playerA, wishcoin); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 6); + assertLife(playerB, 20 - 2); + assertDamageReceived(playerB, wishcoin, 4); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + + + @Test + public void testSpellDamagePlayerAndControlled() { + setupBattlefield(); + addCard(Zone.HAND, playerA, fury); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fury); + addTarget(playerA, playerB); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20 + 5); + assertLife(playerB, 20 - 4); + assertDamageReceived(playerB, wishcoin, 1); + assertCounterCount(pridemate, CounterType.P1P1, 1); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java index 0a24dab7a21..a0a5689a376 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/CantAttackOrBlockAloneTest.java @@ -88,16 +88,35 @@ public class CantAttackOrBlockAloneTest extends CardTestPlayerBase { @Test public void testCantBlockAlone2() { addCard(Zone.BATTLEFIELD, playerA, "Mogg Flunkies"); - addCard(Zone.BATTLEFIELD, playerA, "Llanowar Elves"); + addCard(Zone.BATTLEFIELD, playerA, "Ember Beast"); addCard(Zone.BATTLEFIELD, playerB, "Elite Vanguard"); attack(2, playerB, "Elite Vanguard"); block(2, playerA, "Mogg Flunkies", "Elite Vanguard"); - block(2, playerA, "Llanowar Elves", "Elite Vanguard"); + block(2, playerA, "Ember Beast", "Elite Vanguard"); setStopAt(2, PhaseStep.END_TURN); execute(); assertLife(playerA, 20); } + + /** + * Try to attack with three Orcish Conscripts (can't attack unless 2 others attack) + */ + @Test + public void testCanAttackWithThree() { + addCard(Zone.BATTLEFIELD, playerA, "Orcish Conscripts", 3); // 2/2 + + attack(1, playerA, "Orcish Conscripts"); + attack(1, playerA, "Orcish Conscripts"); + attack(1, playerA, "Orcish Conscripts"); + + setStopAt(1, PhaseStep.END_TURN); + setStrictChooseMode(true); + execute(); + + assertLife(playerB, 14); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/CommanderTypeTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/CommanderTypeTest.java new file mode 100644 index 00000000000..607324085ae --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/CommanderTypeTest.java @@ -0,0 +1,76 @@ +package org.mage.test.commander; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommander4Players; + +public class CommanderTypeTest extends CardTestCommander4Players { + + /* + Sephiroth, Fabled SOLDIER + {2}{B} + Legendary Creature - Human Avatar Soldier + Whenever Sephiroth enters or attacks, you may sacrifice another creature. If you do, draw a card. + Whenever another creature dies, target opponent loses 1 life and you gain 1 life. If this is the fourth time this ability has resolved this turn, transform Sephiroth. + 3/3 + */ + private static final String sephirothFabledSOLDIER = "Sephiroth, Fabled SOLDIER"; + + /* + Sephiroth, One-Winged Angel + Legendary Creature - Angel Nightmare Avatar + Flying + Super Nova -- As this creature transforms into Sephiroth, One-Winged Angel, you get an emblem with "Whenever a creature dies, target opponent loses 1 life and you gain 1 life." + Whenever Sephiroth attacks, you may sacrifice any number of other creatures. If you do, draw that many cards. + 5/5 + */ + private static final String sephirothOneWingedAngel = "Sephiroth, One-Winged Angel"; + + /* + Grizzly Bears + {1}{G} + Creature - Bear + + 2/2 + */ + private static final String grizzlyBears = "Grizzly Bears"; + + @Test + public void testCommanderTypeTransform() { + addCustomEffect_TargetDestroy(playerA); + addCard(Zone.COMMAND, playerA, sephirothFabledSOLDIER); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8); + addCard(Zone.BATTLEFIELD, playerA, grizzlyBears, 5); + + // Cast commander + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sephirothFabledSOLDIER); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + setChoice(playerA, "Yes"); // Sacrifice another creature to draw a card + setChoice(playerA, grizzlyBears); + + // Trigger death of another creature 5 times to transform + addTarget(playerA, playerB, 6); + for (int i = 0; i < 4; i++) { + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy", grizzlyBears); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + } + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy", sephirothOneWingedAngel); + setChoice(playerA, "Yes"); // move to command zone + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // re-cast commander + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sephirothFabledSOLDIER); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerB, 20 - 6); + assertLife(playerA, 20 + 6); + assertPermanentCount(playerA, sephirothFabledSOLDIER, 1); + assertGraveyardCount(playerA, grizzlyBears, 5); + assertEmblemCount(playerA, 1); // Emblem from second side + } +} 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 4d910579aca..133d92dd28a 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 @@ -7,6 +7,8 @@ import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectsList; import mage.cards.Card; +import mage.cards.DoubleFacedCard; +import mage.cards.DoubleFacedCardHalf; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.decks.importer.DeckImporter; @@ -773,6 +775,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement if (gameZone == Zone.BATTLEFIELD) { for (int i = 0; i < count; i++) { Card newCard = cardInfo.createCard(); + if (newCard instanceof DoubleFacedCard) { + DoubleFacedCardHalf rightHalf = ((DoubleFacedCard) newCard).getRightHalfCard(); + if (rightHalf.getName().equals(cardName) && rightHalf.isPermanent()) { + newCard = rightHalf; + } + } getBattlefieldCards(player).add(new PutToBattlefieldInfo( newCard, tapped @@ -781,7 +789,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement // TODO: is it bugged with double faced cards (wrong ref)? // add to all players String aliasId = player.generateAliasName(aliasName, useAliasMultiNames, i + 1); - currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, newCard.getId())); + Card finalNewCard = newCard; + currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, finalNewCard.getId())); } } } else { @@ -2037,7 +2046,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * multiple targets can be seperated by ^; * no target marks as TestPlayer.NO_TARGET; * warning, do not support cards with target adjusters - use addTarget instead - * @param waitStackResolved if true, wait for stack to resolve + * @param waitStackResolved if true, wait for stack to resolve before continuing */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, boolean waitStackResolved) { castSpell(turnNum, step, player, cardName, targetName); 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 index bc6b62530da..7c5eeb066f8 100644 --- 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 @@ -143,6 +143,28 @@ public class CommanderDeckValidationTest extends MageTestPlayerBase { ); } + @Test + public void testPartnerVariants() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Swamp", 98); + + deckTester.addSideboard("Ellie, Vengeful Hunter", 1); + deckTester.addSideboard("Joel, Resolute Survivor", 1); + + deckTester.validate("You can have two commanders if they both have the same Partner variant"); + } + + @Test(expected = AssertionError.class) + public void testPartnerVariants2() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Mountain", 98); + + deckTester.addSideboard("Ellie, Vengeful Hunter", 1); + deckTester.addSideboard("Atreus, Impulsive Son", 1); + + deckTester.validate("You can't have two commanders if they don't have the same Partner variant"); + } + @Test() public void testVehicles1() { DeckTester deckTester = new DeckTester(new Commander()); diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java b/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java index e5441d0bca3..f3fc84ebec7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java @@ -56,8 +56,9 @@ public class AliasesApiTest extends CardTestPlayerBase { Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed // Dangerous", currentGame)); Assert.assertTrue(CardUtil.haveSameNames(splitCard1, splitCard1)); Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other // Dangerous", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Armed // Other", currentGame)); + // The below don't seem to matter/be correct, so they've been disabled. + //Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other // Dangerous", currentGame)); + //Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Armed // Other", currentGame)); Assert.assertFalse(CardUtil.haveSameNames(splitCard1, splitCard2)); // name with face down spells: face down spells don't have names, see https://github.com/magefree/mage/issues/6569 diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java index 99e6845c60c..cd9f1eeda17 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/CardUtilTest.java @@ -21,7 +21,7 @@ public class CardUtilTest extends CardTestPlayerBase { // MDFC where both sides should be playable private static final String birgi = "Birgi, God of Storytelling"; // {2}{R}, frontside of Harnfel private static final String harnfel = "Harnfel, Horn of Bounty"; // {4}{R}, backside of Birgi - + private static final String tamiyo = "Tamiyo, Inquisitive Student"; // {U}, TDFC /** * Test that it will for trigger for discarding a MDFC but will only let you cast the nonland side. */ @@ -122,4 +122,29 @@ public class CardUtilTest extends CardTestPlayerBase { Assert.assertEquals("12345", CardUtil.substring(str, 8, ending)); Assert.assertEquals("12345", CardUtil.substring(str, 9, ending)); } + + /** + * Test that it will for trigger for discarding a TDFC but will only let you cast the front side. + */ + @Test + public void cantPlayTDFCBackSide() { + addCard(Zone.HAND, playerA, changeOfFortune); + addCard(Zone.HAND, playerA, tamiyo); + + addCard(Zone.BATTLEFIELD, playerA, oskar); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + skipInitShuffling(); + setStrictChooseMode(true); + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 4); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, changeOfFortune); + setChoice(playerA, "Yes"); + // only option is to cast front side, so auto chosen + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertPermanentCount(playerA, tamiyo, 1); + } } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 9bb9ed2c176..8db8b3fd823 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -170,14 +170,12 @@ 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, "SPM", "Superior Foes of Spider-Man"); // temporary // subtype // skipListAddName(SKIP_LIST_SUBTYPE, set, cardName); skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Miss Demeanor"); // uses multiple types as a joke card: Lady, of, Proper, Etiquette skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Elvish Impersonators"); // subtype is "Elves" pun skipListAddName(SKIP_LIST_SUBTYPE, "UND", "Elvish Impersonators"); - skipListAddName(SKIP_LIST_SUBTYPE, "SPM", "Superior Foes of Spider-Man"); // temporary // number // skipListAddName(SKIP_LIST_NUMBER, set, cardName); @@ -185,7 +183,7 @@ public class VerifyCardDataTest { // rarity // skipListAddName(SKIP_LIST_RARITY, set, cardName); skipListAddName(SKIP_LIST_RARITY, "CMR", "The Prismatic Piper"); // Collation is not yet set up for CMR https://www.lethe.xyz/mtg/collation/cmr.html - skipListAddName(SKIP_LIST_RARITY, "SPM", "Gwenom, Remorseless"); // temporary + skipListAddName(SKIP_LIST_RARITY, "TLE", "Teferi's Protection"); // temporary // missing abilities // skipListAddName(SKIP_LIST_MISSING_ABILITIES, set, cardName); @@ -306,7 +304,8 @@ public class VerifyCardDataTest { */ private static boolean evergreenCheck(String s) { return evergreenKeywords.contains(s) || s.startsWith("protection from") || s.startsWith("hexproof from") - || s.startsWith("ward ") || s.startsWith("rampage ") || s.startsWith("annihilator"); + || s.startsWith("ward ") || s.startsWith("rampage ") || s.startsWith("annihilator") + || s.matches("^firebending \\d"); } private static boolean eqSet(Collection a, Collection b) { @@ -330,7 +329,8 @@ public class VerifyCardDataTest { checkWrongAbilitiesTextStart(); int cardIndex = 0; - for (Card card : CardScanner.getAllCards()) { + List allCards = CardScanner.getAllCards(); + for (Card card : allCards) { cardIndex++; if (card instanceof CardWithHalves) { check(((CardWithHalves) card).getLeftHalfCard(), cardIndex); @@ -347,7 +347,7 @@ public class VerifyCardDataTest { printMessages(outputMessages); if (failed > 0) { - Assert.fail(String.format("found %d errors in %d cards verify (see errors list above)", failed, CardScanner.getAllCards().size())); + Assert.fail(String.format("found %d errors in %d cards verify (see errors list above)", failed, allCards.size())); } } @@ -651,6 +651,9 @@ public class VerifyCardDataTest { CardInfo cardInfo = CardRepository.instance.findCardsByClass(info.getCardClass().getCanonicalName()).stream().findFirst().orElse(null); Assert.assertNotNull(cardInfo); + if (cardInfo.isDoubleFacedCard()) { + break; + } Card card = cardInfo.createCard(); Card secondCard = card.getSecondCardFace(); if (secondCard != null) { @@ -761,22 +764,26 @@ public class VerifyCardDataTest { continue; } - // CHECK: poster promoType and/or textless must use full art setting - if (((jsonCard.promoTypes != null && jsonCard.promoTypes.contains("poster")) || jsonCard.isTextless) && !card.isFullArt()) { - errorsList.add("Error: card must use full art setting: " - + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); - } - // CHECK: full art lands must use full art setting + // CHECK: non-full art lands must not use full art setting + // CHECK: if full art land is using full art setting, don't perform retro or poster tests boolean isLand = card.getRarity().equals(Rarity.LAND); if (isLand && jsonCard.isFullArt && !card.isFullArt()) { errorsList.add("Error: card must use full art lands setting: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); + continue; + } else if (isLand && !jsonCard.isFullArt && card.isFullArt()) { + errorsList.add("Error: card must NOT use full art lands setting: " + + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); + continue; + } else if (isLand && jsonCard.isFullArt && card.isFullArt()) { + // Land full art is correct, skip other tests + continue; } - // CHECK: non-full art lands must not use full art setting - if (isLand && !jsonCard.isFullArt && card.isFullArt()) { - errorsList.add("Error: card must NOT use full art lands setting: " + // CHECK: poster promoType and/or textless must use full art setting + if (((jsonCard.promoTypes != null && jsonCard.promoTypes.contains("poster")) || jsonCard.isTextless) && !card.isFullArt()) { + errorsList.add("Error: card must use full art setting: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); } @@ -957,13 +964,12 @@ public class VerifyCardDataTest { private static final Set ignoreBoosterSets = new HashSet<>(); static { - // temporary, TODO: remove after set release and mtgjson get info - ignoreBoosterSets.add("Edge of Eternities"); - // jumpstart, TODO: must implement from JumpstartPoolGenerator, see #13264 + // jumpstart, TODO: implement from JumpstartPoolGenerator, see #13264 ignoreBoosterSets.add("Jumpstart"); ignoreBoosterSets.add("Jumpstart 2022"); ignoreBoosterSets.add("Foundations Jumpstart"); ignoreBoosterSets.add("Ravnica: Clue Edition"); + ignoreBoosterSets.add("Avatar: The Last Airbender Eternal"); // joke or un-sets, low implemented cards ignoreBoosterSets.add("Unglued"); ignoreBoosterSets.add("Unhinged"); @@ -1222,7 +1228,8 @@ public class VerifyCardDataTest { cardInfo.getCardNumber(), cardInfo.getRarity(), cardInfo.getGraphicInfo())); Assert.assertNotNull(card); - if (card.getSecondCardFace() != null) { + //TODO: do we need this check after tdfc rework? + if (card.getSecondCardFace() != null && !(card instanceof DoubleFacedCard)) { containsDoubleSideCards = true; } @@ -2192,7 +2199,8 @@ public class VerifyCardDataTest { // Note that the check includes reminder text, so any keyword ability with reminder text always included in the card text doesn't need to be added // FIN added equip abilities with flavor words, allow for those. There are also cards that affect equip costs or equip abilities, exclude those // Technically Enchant should be in this list, but that's added to the SpellAbility in XMage - Pattern targetKeywordRegexPattern = Pattern.compile("^((.*— )?equip(?! cost| abilit)|bestow|partner with|modular|backup)\\b", Pattern.MULTILINE); + // Earthbend is an action word and thus can be anywhere, the rest are keywords that are always first in the line + Pattern targetKeywordRegexPattern = Pattern.compile("earthbend |^((.*— )?equip(?! cost| abilit)|bestow|partner with|modular|backup)\\b", Pattern.MULTILINE); // Checks for targeted reflexive or delayed triggered abilities, ones that only can trigger as a result of another ability // and thus have their "when" located after a previous statement (detected by a period or comma followed by a space) instead of the start. @@ -2284,11 +2292,25 @@ public class VerifyCardDataTest { fail(card, "abilities", "card has backup but is missing this.addAbility(backupAbility)"); } + // special check: DFC main card should not have abilities + if (card instanceof DoubleFacedCardHalf && !card.getMainCard().getInitAbilities().isEmpty()) { + fail(card, "abilities", "transforming double-faced card should not have abilities on the main card"); + } + + // TODO: remove after transform ability removed + // special check: new DFC implementation should not have transform ability + if (card instanceof DoubleFacedCardHalf && card.getAbilities().containsClass(TransformAbility.class) + && !card.getAbilities().containsClass(DayboundAbility.class) + && !card.getAbilities().containsClass(CraftAbility.class) + && !card.getAbilities().containsClass(SiegeAbility.class)) { + fail(card, "abilities", "new transforming double-faced card should not have transform ability"); + } + // special check: Werewolves front ability should only be on front and vice versa - if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && card.isNightCard()) { + if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && (card.isNightCard() || (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).isBackSide()))) { fail(card, "abilities", "card is a back face werewolf with a front face ability"); } - if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && !card.isNightCard()) { + if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && (!card.isNightCard() && (card instanceof DoubleFacedCardHalf && !((DoubleFacedCardHalf) card).isBackSide()))) { fail(card, "abilities", "card is a front face werewolf with a back face ability"); } @@ -2306,7 +2328,7 @@ public class VerifyCardDataTest { } // special check: siege ability must be used in double faced cards only - if (card.getAbilities().containsClass(SiegeAbility.class) && card.getSecondCardFace() == null) { + if (card.getAbilities().containsClass(SiegeAbility.class) && (card.getSecondCardFace() == null && (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).getOtherSide() == null))) { fail(card, "abilities", "miss second side settings in card with siege ability"); } @@ -2635,14 +2657,14 @@ public class VerifyCardDataTest { if (mageObject.isCreature(game)) { return "this creature"; } - if (mageObject.isLand(game)) { - return "this land"; - } for (SubType subType : selfRefNamedSubtypes) { if (mageObject.hasSubtype(subType, game)) { return "this " + subType.getDescription(); } } + if (mageObject.isLand(game)) { + return "this land"; + } if (mageObject.isBattle(game)) { return "this battle"; } @@ -2766,8 +2788,12 @@ public class VerifyCardDataTest { // format to print main card then spell card card.getInitAbilities().getRules().forEach(this::printAbilityText); ((CardWithSpellOption) card).getSpellCard().getAbilities().getRules().forEach(r -> printAbilityText(r.replace("— ", "\n"))); - } else if (card instanceof SplitCard || card instanceof ModalDoubleFacedCard) { - card.getAbilities().getRules().forEach(this::printAbilityText); + } else if (card instanceof SplitCard || card instanceof DoubleFacedCard) { + // format to print each side separately + System.out.println("=== " + ((CardWithHalves) card).getLeftHalfCard().getName() + " ==="); + ((CardWithHalves) card).getLeftHalfCard().getAbilities().getRules().forEach(this::printAbilityText); + System.out.println("=== " + ((CardWithHalves) card).getRightHalfCard().getName() + " ==="); + ((CardWithHalves) card).getRightHalfCard().getAbilities().getRules().forEach(this::printAbilityText); } else { card.getRules().forEach(this::printAbilityText); } @@ -2775,9 +2801,17 @@ public class VerifyCardDataTest { // ref card System.out.println(); MtgJsonCard refMain = MtgJsonService.card(card.getName()); - MtgJsonCard refSpell = null; + Card cardMain = card; + MtgJsonCard refTwo = null; + Card cardTwo = null; if (card instanceof CardWithSpellOption) { - refSpell = MtgJsonService.card(((CardWithSpellOption) card).getSpellCard().getName()); + refTwo = MtgJsonService.card(((CardWithSpellOption) card).getSpellCard().getName()); + cardTwo = ((CardWithSpellOption) card).getSpellCard(); + } else if (card instanceof CardWithHalves) { + refMain = MtgJsonService.card(((CardWithHalves) card).getLeftHalfCard().getName()); + cardMain = ((CardWithHalves) card).getLeftHalfCard(); + refTwo = MtgJsonService.card(((CardWithHalves) card).getRightHalfCard().getName()); + cardTwo = ((CardWithHalves) card).getRightHalfCard(); } if (refMain == null) { refMain = MtgJsonService.cardByClassName(foundClassName); @@ -2785,9 +2819,9 @@ public class VerifyCardDataTest { if (refMain != null) { System.out.println("ref: " + refMain.getNameAsFace() + " " + refMain.manaCost); System.out.println(refMain.text); - if (refSpell != null) { - System.out.println(refSpell.getNameAsFace() + " " + refSpell.manaCost); - System.out.println(refSpell.text); + if (refTwo != null) { + System.out.println("ref: " + refTwo.getNameAsFace() + " " + refTwo.manaCost); + System.out.println(refTwo.text); } } else { System.out.println("WARNING, can't find mtgjson ref for " + card.getName()); @@ -2795,9 +2829,10 @@ public class VerifyCardDataTest { // additional check to simulate diff in rules if (refMain != null) { - checkWrongAbilitiesText(card, refMain, 0, true); - } else if (refSpell != null) { - checkWrongAbilitiesText(((CardWithSpellOption) card).getSpellCard(), refSpell, 0, true); + checkWrongAbilitiesText(cardMain, refMain, 0, true); + } + if (refTwo != null) { + checkWrongAbilitiesText(cardTwo, refTwo, 0, true); } }); } diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java index 08224c3a446..551431e689d 100644 --- a/Mage/src/main/java/mage/MageIdentifier.java +++ b/Mage/src/main/java/mage/MageIdentifier.java @@ -62,6 +62,7 @@ public enum MageIdentifier { DemilichAlternateCast, DemonicEmbraceAlternateCast, FalcoSparaPactweaverAlternateCast, + FireLordOzaiAlternateCast, HelbruteAlternateCast, IntoThePitAlternateCast, MaestrosAscendencyAlternateCast, diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index afe43785d56..af9c1ec624e 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -33,6 +33,7 @@ import mage.game.events.BatchEvent; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.game.stack.StackAbility; import mage.players.Player; @@ -1707,15 +1708,17 @@ public abstract class AbilityImpl implements Ability { private int getCurrentSourceObjectZoneChangeCounter(Game game){ int zcc = game.getState().getZoneChangeCounter(getSourceId()); - // TODO: Enable this, #13710 - /*if (game.getPermanentEntering(getSourceId()) != null){ + Permanent p = game.getPermanentEntering(getSourceId()); + if (p != null && !(p instanceof PermanentToken)){ // If the triggered ability triggered while the permanent is entering the battlefield // then add 1 zcc so that it triggers as if the permanent was already on the battlefield // So "Enters with counters" causes "Whenever counters are placed" to trigger with battlefield zcc // Particularly relevant for Sagas, which always involve both // Note that this does NOT apply to "As ~ ETB" effects, those still use the stack zcc + // TODO: JayDi doesn't like this solution, consider finding another one. zcc += 1; - }*/ + // However, tokens don't change their zcc upon entering the battlefield, so don't add for them + } return zcc; } diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbility.java b/Mage/src/main/java/mage/abilities/TriggeredAbility.java index 37785373766..7d0dd8401dc 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbility.java @@ -61,6 +61,8 @@ public interface TriggeredAbility extends Ability { */ int getRemainingTriggersLimitEachGame(Game game); + TriggeredAbility setOptional(boolean optional); + TriggeredAbility setDoOnlyOnceEachTurn(boolean doOnlyOnce); /** diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index 171669368c5..fcef0db4a28 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -209,6 +209,12 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge return this; } + @Override + public TriggeredAbility setOptional(boolean optional) { + this.optional = optional; + return this; + } + @Override public TriggeredAbility withRuleTextReplacement(boolean replaceRuleText) { this.replaceRuleText = replaceRuleText; diff --git a/Mage/src/main/java/mage/abilities/abilityword/EerieAbility.java b/Mage/src/main/java/mage/abilities/abilityword/EerieAbility.java index c12c9e4e76f..8ecf2d7b424 100644 --- a/Mage/src/main/java/mage/abilities/abilityword/EerieAbility.java +++ b/Mage/src/main/java/mage/abilities/abilityword/EerieAbility.java @@ -9,7 +9,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * TODO: This only triggers off of enchantments entering as the room mechanic hasn't been implemented yet * * @author TheElk801 */ @@ -41,15 +40,23 @@ public class EerieAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD + || event.getType() == GameEvent.EventType.ROOM_FULLY_UNLOCKED; } @Override public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId())) { - return false; + if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null && permanent.isEnchantment(game); } - Permanent permanent = game.getPermanent(event.getTargetId()); - return permanent != null && permanent.isEnchantment(game); + + if (event.getType() == GameEvent.EventType.ROOM_FULLY_UNLOCKED) { + return isControlledBy(event.getPlayerId()); + } + return false; } } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageAttachedTriggeredAbility.java index a1f6f9c286f..532c2ea65e1 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageAttachedTriggeredAbility.java @@ -29,8 +29,7 @@ public class DealsDamageAttachedTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT - || event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + return event.getType() == GameEvent.EventType.DAMAGED_BATCH_BY_SOURCE; } @Override diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java index 0a8aeb373d6..10df3b1f3dd 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldTriggeredAbility.java @@ -23,7 +23,7 @@ public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl { } public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional) { - super(Zone.ALL, effect, optional); // Zone.All because a creature with trigger can be put into play and be sacrificed during the resolution of an effect (discard Obstinate Baloth with Smallpox) + super(Zone.BATTLEFIELD, effect, optional); // Zone.All doesn't appear to be necessary anymore (discard Obstinate Baloth with Smallpox still works) this.withRuleTextReplacement(true); // default true to replace "{this}" with "it" or "this creature" // warning, it's impossible to add text auto-replacement for creatures here (When this creature enters), diff --git a/Mage/src/main/java/mage/abilities/common/OneOrMoreDamagePlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OneOrMoreDamagePlayerTriggeredAbility.java index 706bf44e5ed..3ecbc0656e6 100644 --- a/Mage/src/main/java/mage/abilities/common/OneOrMoreDamagePlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/OneOrMoreDamagePlayerTriggeredAbility.java @@ -1,5 +1,6 @@ package mage.abilities.common; +import mage.MageObjectReference; import mage.abilities.BatchTriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -13,13 +14,17 @@ import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; /** * @author Xanderhall, xenohedron */ -public class OneOrMoreDamagePlayerTriggeredAbility extends TriggeredAbilityImpl implements BatchTriggeredAbility { +public class OneOrMoreDamagePlayerTriggeredAbility extends TriggeredAbilityImpl implements BatchTriggeredAbility { private final SetTargetPointer setTargetPointer; private final FilterPermanent filter; @@ -85,6 +90,16 @@ public class OneOrMoreDamagePlayerTriggeredAbility extends TriggeredAbilityImpl case PLAYER: this.getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId())); break; + case PERMANENT: + Set attackerSet = events + .stream() + .map(GameEvent::getSourceId) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(permanent -> new MageObjectReference(permanent, game)) + .collect(Collectors.toSet()); + this.getAllEffects().setTargetPointer(new FixedTargets(attackerSet)); + break; case NONE: break; default: diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java index e36231d922b..5703d94fe60 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java @@ -17,6 +17,9 @@ 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 LevelX2 @@ -99,11 +102,10 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { + UUID cardId = CardUtil.getMainCardId(game, source.getSourceId()); // for split cards if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD - && event.getTargetId().equals(source.getSourceId())) { - if (condition == null || condition.apply(game, source)) { - return true; - } + && (event.getTargetId().equals(cardId) || event.getTargetId().equals(source.getSourceId()))) { + return condition == null || condition.apply(game, source); } return false; } diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java new file mode 100644 index 00000000000..072eb4ba031 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/PutIntoLibraryOneOrMoreTriggeredAbility.java @@ -0,0 +1,60 @@ +package mage.abilities.common; + +import mage.abilities.BatchTriggeredAbility; +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.events.ZoneChangeBatchEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.Objects; + +/** + * @author TheElk801 + */ +public class PutIntoLibraryOneOrMoreTriggeredAbility extends TriggeredAbilityImpl implements BatchTriggeredAbility { + + public PutIntoLibraryOneOrMoreTriggeredAbility(Effect effect) { + this(effect, false); + } + + public PutIntoLibraryOneOrMoreTriggeredAbility(Effect effect, boolean optional) { + this(Zone.BATTLEFIELD, effect, optional); + } + + public PutIntoLibraryOneOrMoreTriggeredAbility(Zone zone, Effect effect, boolean optional) { + super(zone, effect, optional); + this.setTriggerPhrase("Whenever one or more cards are put into a library from anywhere, "); + } + + private PutIntoLibraryOneOrMoreTriggeredAbility(final PutIntoLibraryOneOrMoreTriggeredAbility ability) { + super(ability); + } + + @Override + public PutIntoLibraryOneOrMoreTriggeredAbility copy() { + return new PutIntoLibraryOneOrMoreTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE_BATCH; + } + + @Override + public boolean checkEvent(ZoneChangeEvent event, Game game) { + return Zone.LIBRARY.match(event.getToZone()); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return this + .getFilteredEvents((ZoneChangeBatchEvent) event, game) + .stream() + .map(GameEvent::getTargetId) + .map(game::getCard) + .anyMatch(Objects::nonNull); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/RoomAbility.java b/Mage/src/main/java/mage/abilities/common/RoomAbility.java new file mode 100644 index 00000000000..36c689f10a5 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/RoomAbility.java @@ -0,0 +1,39 @@ +package mage.abilities.common; + +import mage.abilities.effects.common.RoomCharacteristicsEffect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentImpl; + +// For the overall Room card flavor text and mana value effect. +public class RoomAbility extends SimpleStaticAbility { + public RoomAbility() { + super(Zone.BATTLEFIELD, new RoomCharacteristicsEffect()); + this.setRuleVisible(true); + this.setRuleAtTheTop(true); + } + + protected RoomAbility(final RoomAbility ability) { + super(ability); + } + + @Override + public String getRule() { + return "(You may cast either half. That door unlocks on the battlefield. " + + "As a sorcery, you may pay the mana cost of a locked door to unlock it.)"; + } + + @Override + public RoomAbility copy() { + return new RoomAbility(this); + } + + public void applyCharacteristics(Game game, Permanent permanent) { + ((RoomCharacteristicsEffect) this.getEffects().get(0)).removeCharacteristics(game, permanent); + } + + public void restoreUnlockedStats(Game game, PermanentImpl permanent) { + ((RoomCharacteristicsEffect) this.getEffects().get(0)).restoreUnlockedStats(game, permanent); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java b/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java new file mode 100644 index 00000000000..6c4786fcd39 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/RoomUnlockAbility.java @@ -0,0 +1,109 @@ +package mage.abilities.common; + +import mage.abilities.Ability; +import mage.abilities.SpecialAction; +import mage.abilities.condition.common.RoomHalfLockedCondition; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.TimingRule; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * Special action for Room cards to unlock a locked half by paying its + * mana cost. + * This ability is only present if the corresponding half is currently + * locked. + * @author oscscull + */ +public class RoomUnlockAbility extends SpecialAction { + + private final boolean isLeftHalf; + + public RoomUnlockAbility(ManaCosts costs, boolean isLeftHalf) { + super(Zone.BATTLEFIELD, null); + this.addCost(costs); + + this.isLeftHalf = isLeftHalf; + this.timing = TimingRule.SORCERY; + + // only works if the relevant half is *locked* + if (isLeftHalf) { + this.setCondition(RoomHalfLockedCondition.LEFT); + } else { + this.setCondition(RoomHalfLockedCondition.RIGHT); + } + + // Adds the effect to pay + unlock the half + this.addEffect(new RoomUnlockHalfEffect(isLeftHalf)); + } + + protected RoomUnlockAbility(final RoomUnlockAbility ability) { + super(ability); + this.isLeftHalf = ability.isLeftHalf; + } + + @Override + public RoomUnlockAbility copy() { + return new RoomUnlockAbility(this); + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder(); + sb.append(getManaCostsToPay().getText()).append(": "); + sb.append("Unlock the "); + sb.append(isLeftHalf ? "left" : "right").append(" half."); + sb.append(" (Activate only as a sorcery, and only if the "); + sb.append(isLeftHalf ? "left" : "right").append(" half is locked.)"); + return sb.toString(); + } + + public boolean isLeftHalf() { + return isLeftHalf; + } +} + +/** + * Allows you to pay to unlock the door + */ +class RoomUnlockHalfEffect extends OneShotEffect { + + private final boolean isLeftHalf; + + public RoomUnlockHalfEffect(boolean isLeftHalf) { + super(Outcome.Neutral); + this.isLeftHalf = isLeftHalf; + staticText = "unlock the " + (isLeftHalf ? "left" : "right") + " half"; + } + + private RoomUnlockHalfEffect(final RoomUnlockHalfEffect effect) { + super(effect); + this.isLeftHalf = effect.isLeftHalf; + } + + @Override + public RoomUnlockHalfEffect copy() { + return new RoomUnlockHalfEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + + if (permanent == null) { + return false; + } + + if (isLeftHalf && permanent.isLeftDoorUnlocked()) { + return false; + } + if (!isLeftHalf && permanent.isRightDoorUnlocked()) { + return false; + } + + return permanent.unlockDoor(game, source, isLeftHalf); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java b/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java index 5adbff755f5..8b3dfd4eeff 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellTransformedAbility.java @@ -7,6 +7,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; +import mage.cards.TransformingDoubleFacedCard; import mage.constants.*; import mage.game.Game; import mage.game.stack.Spell; @@ -20,6 +21,7 @@ import java.util.UUID; public class SpellTransformedAbility extends SpellAbility { protected final String manaCost; //This variable is only used for rules text + private boolean ignoreTransformEffect; // TODO: temporary while converting tdfc public SpellTransformedAbility(Card card, String manaCost) { super(card.getSecondFaceSpellAbility()); @@ -35,7 +37,11 @@ public class SpellTransformedAbility extends SpellAbility { this.clearManaCosts(); this.clearManaCostsToPay(); this.addCost(new ManaCostsImpl<>(manaCost)); - this.addSubAbility(new TransformAbility()); + if (!(card instanceof TransformingDoubleFacedCard)) { + this.addSubAbility(new TransformAbility()); + } else { + ignoreTransformEffect = true; + } } public SpellTransformedAbility(final SpellAbility ability) { @@ -54,6 +60,7 @@ public class SpellTransformedAbility extends SpellAbility { protected SpellTransformedAbility(final SpellTransformedAbility ability) { super(ability); this.manaCost = ability.manaCost; + this.ignoreTransformEffect = ability.ignoreTransformEffect; } @Override @@ -65,6 +72,9 @@ public class SpellTransformedAbility extends SpellAbility { public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { if (super.activate(game, allowedIdentifiers, noMana)) { game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE); + if (ignoreTransformEffect) { + return true; + } // TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides) TransformedEffect effect = new TransformedEffect(); game.addEffect(effect, this); diff --git a/Mage/src/main/java/mage/abilities/common/UnlockThisDoorTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/UnlockThisDoorTriggeredAbility.java new file mode 100644 index 00000000000..752ba6e5b6f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/UnlockThisDoorTriggeredAbility.java @@ -0,0 +1,43 @@ +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; + +/** + * Triggered ability for "when you unlock this door" effects + * + * @author oscscull + */ +public class UnlockThisDoorTriggeredAbility extends TriggeredAbilityImpl { + + private final boolean isLeftHalf; + + public UnlockThisDoorTriggeredAbility(Effect effect, boolean optional, boolean isLeftHalf) { + super(Zone.BATTLEFIELD, effect, optional); + this.isLeftHalf = isLeftHalf; + this.setTriggerPhrase("When you unlock this door, "); + } + + private UnlockThisDoorTriggeredAbility(final UnlockThisDoorTriggeredAbility ability) { + super(ability); + this.isLeftHalf = ability.isLeftHalf; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DOOR_UNLOCKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getTargetId().equals(getSourceId()) && event.getFlag() == isLeftHalf; + } + + @Override + public UnlockThisDoorTriggeredAbility copy() { + return new UnlockThisDoorTriggeredAbility(this); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/common/delayed/ReflexiveTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/ReflexiveTriggeredAbility.java index 2c4cc9afc07..a6d0387fc46 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/ReflexiveTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/ReflexiveTriggeredAbility.java @@ -14,7 +14,6 @@ import mage.util.CardUtil; public class ReflexiveTriggeredAbility extends DelayedTriggeredAbility { private final String text; - private final Condition condition; public ReflexiveTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, null); @@ -27,13 +26,14 @@ public class ReflexiveTriggeredAbility extends DelayedTriggeredAbility { public ReflexiveTriggeredAbility(Effect effect, boolean optional, String text, Condition condition) { super(effect, Duration.EndOfTurn, true, optional); this.text = text; - this.condition = condition; + if (condition != null) { + this.withInterveningIf(condition); + } } protected ReflexiveTriggeredAbility(final ReflexiveTriggeredAbility ability) { super(ability); this.text = ability.text; - this.condition = ability.condition; } @Override @@ -55,11 +55,6 @@ public class ReflexiveTriggeredAbility extends DelayedTriggeredAbility { return CardUtil.getTextWithFirstCharUpperCase(text) + '.'; } - @Override - public boolean checkInterveningIfClause(Game game) { - return condition == null || condition.apply(game, this); - } - @Override public ReflexiveTriggeredAbility setTriggerPhrase(String triggerPhrase) { super.setTriggerPhrase(triggerPhrase); diff --git a/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java new file mode 100644 index 00000000000..6a71b11474c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CastNoncreatureSpellThisTurnCondition.java @@ -0,0 +1,35 @@ +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.SpellsCastWatcher; + +/** + * @author TheElk801 + */ +public enum CastNoncreatureSpellThisTurnCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getWatcher(SpellsCastWatcher.class) + .getSpellsCastThisTurn(source.getControllerId()) + .stream() + .anyMatch(spell -> !spell.isCreature(game)); + } + + @Override + public String toString() { + return "you've cast a noncreature spell this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.java new file mode 100644 index 00000000000..b8356474519 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CreatureLeftThisTurnCondition.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.CreatureLeftBattlefieldWatcher; + +/** + * @author TheElk801 + */ +public enum CreatureLeftThisTurnCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return CreatureLeftBattlefieldWatcher.getNumberCreatureLeft(source.getControllerId(), game) > 0; + } + + @Override + public String toString() { + return "a creature left the battlefield under your control this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/IsMainPhaseCondition.java b/Mage/src/main/java/mage/abilities/condition/common/IsMainPhaseCondition.java index 4d10747d907..d832a21d774 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/IsMainPhaseCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/IsMainPhaseCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -10,23 +9,22 @@ import mage.game.Game; */ public enum IsMainPhaseCondition implements Condition { - YOUR(true), - ANY(false); + YOURS(true), + NOT_YOURS(false); - private final boolean yourMainPhaseOnly; + private final boolean yours; - IsMainPhaseCondition(boolean yourMainPhaseOnly) { - this.yourMainPhaseOnly = yourMainPhaseOnly; + IsMainPhaseCondition(boolean yours) { + this.yours = yours; } @Override public boolean apply(Game game, Ability source) { - return game.getTurnPhaseType().isMain() && - (!yourMainPhaseOnly || game.getActivePlayerId().equals(source.getControllerId())); + return game.getTurnPhaseType().isMain() && yours == game.isActivePlayer(source.getControllerId()); } @Override public String toString() { - return "it's" + (yourMainPhaseOnly ? " your " : " ") + "main phase"; + return "it" + (yours ? "'s" : " isn't") + " your main phase"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/LessonsInGraveCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LessonsInGraveCondition.java new file mode 100644 index 00000000000..2c2f00f2fe1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/LessonsInGraveCondition.java @@ -0,0 +1,45 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public enum LessonsInGraveCondition implements Condition { + ONE(1), + THREE(3); + private final int amount; + private static final FilterCard filter = new FilterCard(SubType.LESSON); + private static final Hint hint = new ValueHint("Lesson cards in your graveyard", new CardsInControllerGraveyardCount(filter)); + + public static Hint getHint() { + return hint; + } + + LessonsInGraveCondition(int amount) { + this.amount = amount; + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.getGraveyard().count(filter, game) >= this.amount; + } + + @Override + public String toString() { + if (amount == 1) { + return "there's a Lesson card in your graveyard"; + } + return "there are " + CardUtil.numberToText(this.amount) + " or more Lesson cards in your graveyard"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/RoomHalfLockedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RoomHalfLockedCondition.java new file mode 100644 index 00000000000..7b7bc266ff5 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/RoomHalfLockedCondition.java @@ -0,0 +1,34 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author oscscull + * Checks if a Permanent's specified half is LOCKED (i.e., NOT unlocked). + */ +public enum RoomHalfLockedCondition implements Condition { + + LEFT(true), + RIGHT(false); + + private final boolean checkLeft; + + RoomHalfLockedCondition(boolean checkLeft) { + this.checkLeft = checkLeft; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + + if (permanent == null) { + return false; + } + + // Return true if the specified half is NOT unlocked + return checkLeft ? !permanent.isLeftDoorUnlocked() : !permanent.isRightDoorUnlocked(); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java new file mode 100644 index 00000000000..03a51bcb2a4 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/WaterbendedCondition.java @@ -0,0 +1,26 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.WaterbendAbility; +import mage.game.Game; +import mage.util.CardUtil; + +/** + * Checks if the spell was cast with the alternate waterbend cost + * + * @author TheElk801 + */ +public enum WaterbendedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return CardUtil.checkSourceCostsTagExists(game, source, WaterbendAbility.WATERBEND_ACTIVATION_VALUE_KEY); + } + + @Override + public String toString() { + return "the additional cost was paid"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouControlABasicLandCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouControlABasicLandCondition.java new file mode 100644 index 00000000000..1bde708b141 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/YouControlABasicLandCondition.java @@ -0,0 +1,38 @@ +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.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public enum YouControlABasicLandCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + + static { + filter.add(SuperType.BASIC.getPredicate()); + } + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().contains(filter, source.getControllerId(), source, game, 1); + } + + @Override + public String toString() { + return "you control a basic land"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouControlALegendaryCreatureCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouControlALegendaryCreatureCondition.java new file mode 100644 index 00000000000..99f509bc1e7 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/YouControlALegendaryCreatureCondition.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.filter.StaticFilters; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public enum YouControlALegendaryCreatureCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().contains(StaticFilters.FILTER_CONTROLLED_CREATURE_LEGENDARY, source.getControllerId(), source, game, 1); + } + + @Override + public String toString() { + return "you control a legendary creature"; + } +} 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 2c5b8ac5552..1c51c8030c7 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java @@ -11,7 +11,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** * @author BetaSteward_at_googlemail.com @@ -21,16 +23,11 @@ public class RemoveCountersSourceCost extends CostImpl { private final int amount; private final String name; - public RemoveCountersSourceCost() { - this.amount = 1; - this.name = ""; - this.text = "remove a counter from {this}"; - } - public RemoveCountersSourceCost(int amount) { this.amount = amount; this.name = ""; - this.text = "remove " + CardUtil.numberToText(amount) + " counters from {this}"; + this.text = "remove " + CardUtil.numberToText(amount, "a") + + " counter" + (amount > 1 ? "s" : "") + " from {this}"; } public RemoveCountersSourceCost(Counter counter) { @@ -87,7 +84,7 @@ public class RemoveCountersSourceCost extends CostImpl { } paid = true; } - } else if (permanent.getCounters(game).getCount(name) >= amount){ + } else if (permanent.getCounters(game).getCount(name) >= amount) { permanent.removeCounters(name, amount, source, game); this.paid = true; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java index e1ea59d094a..db762f8a0cd 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/WaterbendCost.java @@ -2,7 +2,7 @@ package mage.abilities.costs.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.CostImpl; import mage.game.Game; import java.util.UUID; @@ -12,14 +12,14 @@ import java.util.UUID; * * @author TheElk801 */ -public class WaterbendCost extends ManaCostsImpl { +public class WaterbendCost extends CostImpl { public WaterbendCost(int amount) { this("{" + amount + '}'); } public WaterbendCost(String mana) { - super(""); + super(); this.text = "waterbend " + mana; } diff --git a/Mage/src/main/java/mage/abilities/decorator/OptionalOneShotEffect.java b/Mage/src/main/java/mage/abilities/decorator/OptionalOneShotEffect.java new file mode 100644 index 00000000000..13e909391ec --- /dev/null +++ b/Mage/src/main/java/mage/abilities/decorator/OptionalOneShotEffect.java @@ -0,0 +1,91 @@ +package mage.abilities.decorator; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.TargetPointer; +import mage.util.CardUtil; + +/** + * Adds condition to {@link OneShotEffect}. Acts as decorator. + * + * @author Grath + */ +public class OptionalOneShotEffect extends OneShotEffect { + + private final Effects effects = new Effects(); + + public OptionalOneShotEffect(OneShotEffect effect) { + super(effect != null ? effect.getOutcome() : Outcome.Benefit); // must be first line, can't error for null effect here. + if (effect == null) { + throw new IllegalArgumentException("Wrong code usage: OptionalOneShotEffect should start with an effect to generate Outcome."); + } + this.effects.add(effect); + } + + protected OptionalOneShotEffect(final OptionalOneShotEffect effect) { + super(effect); + this.effects.addAll(effect.effects.copy()); + } + + @Override + public boolean apply(Game game, Ability source) { + // nothing to do - no problem + if (effects.isEmpty()) { + return true; + } + Player player = game.getPlayer(source.getControllerId()); + String chooseText = staticText; + if (chooseText == null || chooseText.isEmpty()) { + chooseText = getText(source.getModes().getMode()); + chooseText = Character.toUpperCase(chooseText.charAt(0)) + chooseText.substring(1); + } + if (player != null && player.chooseUse(outcome, chooseText, source, game)) { + effects.setTargetPointer(this.getTargetPointer().copy()); + effects.forEach(effect -> effect.apply(game, source)); + return true; + } + return false; + } + + public OptionalOneShotEffect addEffect(OneShotEffect effect) { + this.effects.add(effect); + return this; + } + + @Override + public void setValue(String key, Object value) { + super.setValue(key, value); + this.effects.setValue(key, value); + } + + @Override + public OptionalOneShotEffect copy() { + return new OptionalOneShotEffect(this); + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "you may " + CardUtil.getTextWithFirstCharLowerCase(effects.getText(mode)); + } + + @Override + public OptionalOneShotEffect setTargetPointer(TargetPointer targetPointer) { + effects.setTargetPointer(targetPointer); + super.setTargetPointer(targetPointer); + return this; + } + + @Override + public OptionalOneShotEffect withTargetDescription(String target) { + effects.forEach(effect -> effect.withTargetDescription(target)); + return this; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/IntPlusDynamicValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/IntPlusDynamicValue.java index 3742630a3ec..0b0d5ee9dbd 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/IntPlusDynamicValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/IntPlusDynamicValue.java @@ -36,14 +36,12 @@ public class IntPlusDynamicValue implements DynamicValue { @Override public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(baseValue).append(" plus "); - return sb.append(value.toString()).toString(); + return baseValue + " plus " + value.toString(); } @Override public String getMessage() { - return value.getMessage(); + return baseValue + " plus " + value.getMessage(); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersControllerCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersControllerCount.java index c6d6a86826b..0d942a10de0 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersControllerCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersControllerCount.java @@ -48,6 +48,6 @@ public class CountersControllerCount implements DynamicValue { @Override public String getMessage() { - return (counterType != null ? counterType.toString() + ' ' : "") + "counter on {this}'s controller"; + return "the number of " + counterType.getName() + " counters you have"; } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java index 51700c964c6..3173e1e8fe9 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsSacrificedThisTurnCount.java @@ -4,6 +4,8 @@ package mage.abilities.dynamicvalue.common; 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.game.Game; import mage.watchers.common.PermanentsSacrificedWatcher; @@ -11,20 +13,27 @@ import mage.watchers.common.PermanentsSacrificedWatcher; * @author Susucr */ public enum PermanentsSacrificedThisTurnCount implements DynamicValue { - instance; + ALL(true), + YOU(false); + private final boolean all; + private final Hint hint; + + PermanentsSacrificedThisTurnCount(boolean all) { + this.all = all; + this.hint = new ValueHint("Permanents " + (all ? "" : "you ") + "sacrificed this turn", this); + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { PermanentsSacrificedWatcher watcher = game.getState().getWatcher(PermanentsSacrificedWatcher.class); - if (watcher != null) { - return watcher.getThisTurnSacrificedPermanents(); - } - return 0; + return this.all + ? watcher.getThisTurnSacrificedPermanents() + : watcher.getThisTurnSacrificedPermanents(sourceAbility.getControllerId()).size(); } @Override public PermanentsSacrificedThisTurnCount copy() { - return PermanentsSacrificedThisTurnCount.instance; + return this; } @Override @@ -34,7 +43,10 @@ public enum PermanentsSacrificedThisTurnCount implements DynamicValue { @Override public String getMessage() { - return "permanents sacrificed this turn"; + return "the number of permanents " + (this.all ? "" : "you've ") + "sacrificed this turn"; } + public Hint getHint() { + return hint; + } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ShrinesYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ShrinesYouControlCount.java new file mode 100644 index 00000000000..10c4b2ef290 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ShrinesYouControlCount.java @@ -0,0 +1,55 @@ +package mage.abilities.dynamicvalue.common; + +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.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public enum ShrinesYouControlCount implements DynamicValue { + WHERE_X("X", "the number of Shrines you control"), + FOR_EACH("1", "Shrine you control"); + + private static final Hint hint = new ValueHint("Shrines you control", WHERE_X); + + public static Hint getHint() { + return hint; + } + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SHRINE); + + private final String number; + private final String message; + + ShrinesYouControlCount(String number, String message) { + this.number = number; + this.message = message; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); + } + + @Override + public ShrinesYouControlCount copy() { + return this; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public String toString() { + return number; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java index 6d8e2d6fea4..2707c3a7a90 100644 --- a/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/AsThoughEffectImpl.java @@ -3,10 +3,7 @@ package mage.abilities.effects; import mage.MageIdentifier; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; -import mage.cards.Card; -import mage.cards.ModalDoubleFacedCard; -import mage.cards.SplitCard; -import mage.cards.CardWithSpellOption; +import mage.cards.*; import mage.constants.*; import mage.game.Game; import mage.players.Player; @@ -92,9 +89,9 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier); Card rightCard = ((SplitCard) card).getRightHalfCard(); player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts(), identifier); - } else if (card instanceof ModalDoubleFacedCard) { - Card leftCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + } else if (card instanceof DoubleFacedCard) { + Card leftCard = ((DoubleFacedCard) card).getLeftHalfCard(); + Card rightCard = ((DoubleFacedCard) card).getRightHalfCard(); // some MDFC's are land. IE: sea gate restoration if (!leftCard.isLand(game)) { player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index 0f9f25acc3a..1b282f109b0 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -248,6 +248,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu return startingControllerId; } + protected int getEffectStartingOnTurn() { + return effectStartingOnTurn; + } + @Override public void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId) { this.startingControllerId = startingController; diff --git a/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java index b8a7b236791..5aeef1bd8d4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/BecomesMonarchTargetEffect.java @@ -13,7 +13,7 @@ public class BecomesMonarchTargetEffect extends OneShotEffect { public BecomesMonarchTargetEffect() { super(Outcome.Benefit); - staticText = "target player becomes the monarch"; + staticText = "target opponent becomes the monarch"; } protected BecomesMonarchTargetEffect(final BecomesMonarchTargetEffect effect) { @@ -34,5 +34,4 @@ public class BecomesMonarchTargetEffect extends OneShotEffect { } return false; } - } 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 f464355448e..bbb9bbfa828 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -2,9 +2,11 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.MageObjectReference; +import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; +import mage.abilities.common.RoomAbility; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; @@ -63,6 +65,16 @@ public class CopyEffect extends ContinuousEffectImpl { permanent = game.getPermanentEntering(copyToObjectId); if (permanent != null) { copyToPermanent(permanent, game, source); + // Apply Room characteristics since effects aren't applied to entering permanents yet + if (permanent.hasSubtype(SubType.ROOM, game)) { + Abilities abilities = permanent.getAbilities(); + for (Ability ability : abilities) { + if (ability instanceof RoomAbility) { + ((RoomAbility) ability).applyCharacteristics(game, permanent); + break; + } + } + } // set reference to the permanent later on the battlefield so we have to add already one (if no token) to the zone change counter int ZCCDiff = 1; if (permanent instanceof PermanentToken) { 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 6f02329d0b3..7f91a769dcc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -58,8 +58,8 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { private final boolean tapped; private Permanent savedPermanent = null; private int startingLoyalty = -1; - private final int tokenPower; - private final int tokenToughness; + private int tokenPower; + private int tokenToughness; private boolean useLKI = false; private PermanentModifier permanentModifier = null; @@ -216,6 +216,28 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { // create token and modify all attributes permanently (without game usage) Token token = CopyTokenFunction.createTokenCopy(copyFrom, game); // needed so that entersBattlefield triggered abilities see the attributes (e.g. Master Biomancer) applier.apply(game, token, source, targetId); + // the active face should have the modified attributes + if (token.isEntersTransformed()) { + applyAdditionsToToken(token.getBackFace()); + } else { + applyAdditionsToToken(token); + } + + token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo); + for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield + Permanent tokenPermanent = game.getPermanent(tokenId); + if (tokenPermanent != null) { + addedTokenPermanents.add(tokenPermanent); + // TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786 + if (counter != null && numberOfCounters > 0) { + tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game); + } + } + } + return true; + } + + private void applyAdditionsToToken(Token token) { if (becomesArtifact) { token.addCardType(CardType.ARTIFACT); } @@ -281,19 +303,6 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { token.removeAbility(ability); } } - - token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo); - for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield - Permanent tokenPermanent = game.getPermanent(tokenId); - if (tokenPermanent != null) { - addedTokenPermanents.add(tokenPermanent); - // TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786 - if (counter != null && numberOfCounters > 0) { - tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game); - } - } - } - return true; } @Override @@ -387,6 +396,16 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { return this; } + public CreateTokenCopyTargetEffect setPower(int tokenPower) { + this.tokenPower = tokenPower; + return this; + } + + public CreateTokenCopyTargetEffect setToughness(int tokenToughness) { + this.tokenToughness = tokenToughness; + return this; + } + public CreateTokenCopyTargetEffect addAbilityClassesToRemoveFromTokens(Class clazz) { this.abilityClazzesToRemove.add(clazz); return this; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java new file mode 100644 index 00000000000..61d228d61ea --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndAllControlledEffect.java @@ -0,0 +1,83 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.Mode; +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; + +/** + * @author xenohedron + */ +public class DamageTargetAndAllControlledEffect extends OneShotEffect { + + private final int firstAmount; + private final int secondAmount; + private final FilterPermanent filter; + + /** + * Deals simultaneous damage to the target and to each creature the target controls + */ + public DamageTargetAndAllControlledEffect(int amount) { + this(amount, amount, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + /** + * Deals simultaneous damage to the target and to each creature the target controls + */ + public DamageTargetAndAllControlledEffect(int firstAmount, int secondAmount, FilterPermanent filter) { + super(Outcome.Damage); + this.firstAmount = firstAmount; + this.secondAmount = secondAmount; + this.filter = filter; + } + + protected DamageTargetAndAllControlledEffect(final DamageTargetAndAllControlledEffect effect) { + super(effect); + this.firstAmount = effect.firstAmount; + this.secondAmount = effect.secondAmount; + this.filter = effect.filter.copy(); + } + + @Override + public DamageTargetAndAllControlledEffect copy() { + return new DamageTargetAndAllControlledEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + permanent.damage(firstAmount, source.getSourceId(), source, game); + } else { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player != null) { + player.damage(firstAmount, source.getSourceId(), source, game); + } + } + Player controller = game.getPlayerOrPlaneswalkerController(getTargetPointer().getFirst(game, source)); + if (controller != null) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { + perm.damage(secondAmount, source.getSourceId(), source, game); + } + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + String description = getTargetPointer().describeTargets(mode.getTargets(), "that player"); + return "{this} deals " + firstAmount + " damage to " + description + " and " + + ((firstAmount == secondAmount) ? "each " : secondAmount + " damage to each ") + + filter.getMessage() + " that player" + + (description.contains("planeswalker") ? " or that planeswalker's controller" : "") + + " controls"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java new file mode 100644 index 00000000000..5ba9fd27c9a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndSelfEffect.java @@ -0,0 +1,77 @@ +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.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public class DamageTargetAndSelfEffect extends OneShotEffect { + + private final int firstAmount; + private final int secondAmount; + + /** + * Deals simultaneous damage to the target and to itself + */ + public DamageTargetAndSelfEffect(int amount) { + this(amount, amount); + } + + /** + * Deals simultaneous damage to the target and to itself + */ + public DamageTargetAndSelfEffect(int firstAmount, int secondAmount) { + super(Outcome.Damage); + this.firstAmount = firstAmount; + this.secondAmount = secondAmount; + } + + protected DamageTargetAndSelfEffect(final DamageTargetAndSelfEffect effect) { + super(effect); + this.firstAmount = effect.firstAmount; + this.secondAmount = effect.secondAmount; + } + + @Override + public DamageTargetAndSelfEffect copy() { + return new DamageTargetAndSelfEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(firstAmount, source.getSourceId(), source, game); + } else { + Player player = game.getPlayer(targetId); + if (player != null) { + player.damage(firstAmount, source.getSourceId(), source, game); + } + } + } + Permanent itself = source.getSourcePermanentIfItStillExists(game); + if (itself != null) { + itself.damage(secondAmount, source.getSourceId(), source, game); + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "{this} deals " + firstAmount + " damage to " + + getTargetPointer().describeTargets(mode.getTargets(), "that creature") + + " and " + secondAmount + " damage to itself"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java new file mode 100644 index 00000000000..0fe2b18aa26 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetControllerEffect.java @@ -0,0 +1,69 @@ +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.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public class DamageTargetAndTargetControllerEffect extends OneShotEffect { + + private final int firstAmount; + private final int secondAmount; + + /** + * Deals simultaneous damage to the target and to the controller of the target + */ + public DamageTargetAndTargetControllerEffect(int firstAmount, int secondAmount) { + super(Outcome.Damage); + this.firstAmount = firstAmount; + this.secondAmount = secondAmount; + } + + protected DamageTargetAndTargetControllerEffect(final DamageTargetAndTargetControllerEffect effect) { + super(effect); + this.firstAmount = effect.firstAmount; + this.secondAmount = effect.secondAmount; + } + + @Override + public DamageTargetAndTargetControllerEffect copy() { + return new DamageTargetAndTargetControllerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(firstAmount, source.getSourceId(), source, game); + } + Permanent lki = game.getPermanentOrLKIBattlefield(targetId); + if (lki != null) { + Player player = game.getPlayer(lki.getControllerId()); + if (player != null) { + player.damage(secondAmount, source.getSourceId(), source, game); + } + } + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + String description = getTargetPointer().describeTargets(mode.getTargets(), "that creature"); + return "{this} deals " + firstAmount + " damage to " + description + + " and " + secondAmount + " damage to that " + + (description.contains(" or ") ? "permanent's" : "creature's") + " controller"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java new file mode 100644 index 00000000000..c5f81072b7d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndTargetEffect.java @@ -0,0 +1,72 @@ +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.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public class DamageTargetAndTargetEffect extends OneShotEffect { + + private final int firstAmount; + private final int secondAmount; + + /** + * Deals simultaneous damage to two targets. Must set target tag 1 and 2 + */ + public DamageTargetAndTargetEffect(int firstAmount, int secondAmount) { + super(Outcome.Damage); + this.firstAmount = firstAmount; + this.secondAmount = secondAmount; + } + + protected DamageTargetAndTargetEffect(final DamageTargetAndTargetEffect effect) { + super(effect); + this.firstAmount = effect.firstAmount; + this.secondAmount = effect.secondAmount; + } + + @Override + public DamageTargetAndTargetEffect copy() { + return new DamageTargetAndTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + source.getTargets().getTargetsByTag(1).forEach(uuid -> damageTarget(uuid, firstAmount, source, game)); + source.getTargets().getTargetsByTag(2).forEach(uuid -> damageTarget(uuid, secondAmount, source, game)); + return true; + } + + private void damageTarget(UUID targetId, int amount, Ability source, Game game) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(amount, source.getSourceId(), source, game) ; + } else { + Player player = game.getPlayer(targetId); + if (player != null) { + player.damage(amount, source.getSourceId(), source, game); + } + } + } + + @Override + public String getText(Mode mode) { + // verify check that target tags are properly setup + if (mode.getTargets().getByTag(1) == null || mode.getTargets().getByTag(2) == null) { + throw new IllegalArgumentException("Wrong code usage: need to add tags to targets"); + } + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "{this} deals " + firstAmount + " damage to " + mode.getTargets().getByTag(1).getDescription() + + " and " + secondAmount + " damage to " + mode.getTargets().getByTag(2).getDescription(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java new file mode 100644 index 00000000000..390d3ff6273 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetAndYouEffect.java @@ -0,0 +1,77 @@ +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.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public class DamageTargetAndYouEffect extends OneShotEffect { + + private final int firstAmount; + private final int secondAmount; + + /** + * Deals simultaneous damage to the target and the controller of the source + */ + public DamageTargetAndYouEffect(int amount) { + this(amount, amount); + } + + /** + * Deals simultaneous damage to the target and the controller of the source + */ + public DamageTargetAndYouEffect(int firstAmount, int secondAmount) { + super(Outcome.Damage); + this.firstAmount = firstAmount; + this.secondAmount = secondAmount; + } + + protected DamageTargetAndYouEffect(final DamageTargetAndYouEffect effect) { + super(effect); + this.firstAmount = effect.firstAmount; + this.secondAmount = effect.secondAmount; + } + + @Override + public DamageTargetAndYouEffect copy() { + return new DamageTargetAndYouEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(firstAmount, source.getSourceId(), source, game); + } else { + Player player = game.getPlayer(targetId); + if (player != null) { + player.damage(firstAmount, source.getSourceId(), source, game); + } + } + } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.damage(secondAmount, source.getSourceId(), source, game); + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "{this} deals " + firstAmount + " damage to " + + getTargetPointer().describeTargets(mode.getTargets(), "that creature") + + " and " + secondAmount + " damage to you"; + } +} 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 ae23687ce8a..4780d137728 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java @@ -4,14 +4,11 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; -import mage.util.CardUtil; import java.util.UUID; @@ -21,92 +18,38 @@ import java.util.UUID; */ public class DamageTargetEffect extends OneShotEffect { - protected DynamicValue amount; - protected boolean preventable; - protected String targetDescription; - protected boolean useOnlyTargetPointer; // TODO: investigate why do we ignore targetPointer by default?? - protected String sourceName = "{this}"; + private final DynamicValue amount; + private boolean preventable = true; + private String sourceName = "{this}"; public DamageTargetEffect(int amount) { - this(StaticValue.get(amount), true); + this(StaticValue.get(amount)); } public DamageTargetEffect(int amount, String whoDealDamageName) { - this(StaticValue.get(amount), true); - this.sourceName = whoDealDamageName; - } - - public DamageTargetEffect(int amount, boolean preventable) { - this(StaticValue.get(amount), preventable); - } - - public DamageTargetEffect(int amount, boolean preventable, String targetDescription) { - this(StaticValue.get(amount), preventable, targetDescription); - } - - public DamageTargetEffect(int amount, boolean preventable, String targetDescription, boolean useOnlyTargetPointer) { - this(StaticValue.get(amount), preventable, targetDescription, useOnlyTargetPointer); - } - - public DamageTargetEffect(int amount, boolean preventable, String targetDescription, String whoDealDamageName) { - this(StaticValue.get(amount), preventable, targetDescription); + this(amount); this.sourceName = whoDealDamageName; } public DamageTargetEffect(DynamicValue amount) { - this(amount, true); + super(Outcome.Damage); + this.amount = amount; } public DamageTargetEffect(DynamicValue amount, String whoDealDamageName) { - this(amount, true); + this(amount); this.sourceName = whoDealDamageName; } - public DamageTargetEffect(DynamicValue amount, boolean preventable) { - this(amount, preventable, ""); - } - - public DamageTargetEffect(DynamicValue amount, boolean preventable, String targetDescription) { - this(amount, preventable, targetDescription, false); - } - - public DamageTargetEffect(DynamicValue amount, boolean preventable, String targetDescription, boolean useOnlyTargetPointer) { - super(Outcome.Damage); - this.amount = amount; - this.preventable = preventable; - this.targetDescription = targetDescription; - this.useOnlyTargetPointer = useOnlyTargetPointer; - } - - public int getAmount() { - if (amount instanceof StaticValue) { - return amount.calculate(null, null, this); - } else { - return 0; - } - } - - public void setAmount(DynamicValue amount) { - this.amount = amount; - } - protected DamageTargetEffect(final DamageTargetEffect effect) { super(effect); this.amount = effect.amount.copy(); this.preventable = effect.preventable; - this.targetDescription = effect.targetDescription; - this.useOnlyTargetPointer = effect.useOnlyTargetPointer; this.sourceName = effect.sourceName; } - public DamageTargetEffect withTargetDescription(String targetDescription) { - this.targetDescription = targetDescription; - return this; - } - - // TODO: this should most likely be refactored to not be needed and always use target pointer. - public Effect setUseOnlyTargetPointer(boolean useOnlyTargetPointer) { - this.useOnlyTargetPointer = useOnlyTargetPointer; + public DamageTargetEffect withCantBePrevented() { + this.preventable = false; return this; } @@ -117,21 +60,6 @@ public class DamageTargetEffect 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.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, preventable); - } - Player player = game.getPlayer(targetId); - if (player != null) { - player.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, preventable); - } - } - } - return true; - } for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -154,46 +82,18 @@ public class DamageTargetEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); String message = amount.getMessage(); sb.append(this.sourceName).append(" deals "); - if (message.isEmpty() || !message.equals("1")) { + if (!message.equals("1")) { sb.append(amount); } if (!sb.toString().endsWith(" ")) { sb.append(' '); } sb.append("damage to "); - if (!targetDescription.isEmpty()) { - sb.append(targetDescription); - } else { - if (!mode.getTargets().isEmpty()) { - Target firstTarget = mode.getTargets().get(0); - String targetName = firstTarget.getTargetName(); - if (targetName.contains("any")) { - sb.append(targetName); - } else { - if (firstTarget.getMinNumberOfTargets() == 0) { - int maxTargets = firstTarget.getMaxNumberOfTargets(); - switch (maxTargets) { - case Integer.MAX_VALUE: - sb.append("any number of "); - break; - case 1: - sb.append("up to one "); - break; - default: - sb.append("each of up to "); - sb.append(CardUtil.numberToText(maxTargets)); - sb.append(' '); - } - } - if (!targetName.contains("target ")) { - sb.append("target "); - } - sb.append(targetName); - } - } else { - sb.append("that target"); - } + String targetDescription = getTargetPointer().describeTargets(mode.getTargets(), "that target"); + if (targetDescription.startsWith("up to") && !targetDescription.startsWith("up to one")) { + sb.append("each of "); } + sb.append(targetDescription); if (!message.isEmpty()) { if (message.equals("1")) { sb.append(" equal to the number of "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java index eacbc21c535..1e8b2c1c4e9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileAndReturnSourceEffect.java @@ -2,11 +2,11 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.constants.Pronoun; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.constants.Pronoun; import mage.constants.PutCards; import mage.constants.Zone; import mage.game.Game; @@ -74,7 +74,7 @@ public class ExileAndReturnSourceEffect extends OneShotEffect { returnUnderYourControl ? controller : game.getPlayer(permanent.getOwnerId()), permanent.getMainCard(), source, game, "card" ); - if (additionalEffect == null || game.getPermanent(permanent.getId()) == null) { + if (additionalEffect == null || !game.getState().getZone(permanent.getMainCard().getId()).equals(Zone.BATTLEFIELD)) { return true; } if (additionalEffect instanceof ContinuousEffect) { 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 67307e1916b..a49c919887c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java @@ -54,6 +54,7 @@ public class GainLifeEffect extends OneShotEffect { @Override public String getText(Mode mode) { + // TODO: this text generation probably needs reworking if (staticText != null && !staticText.isEmpty()) { return staticText; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java index a47aa31f40b..ab93c997e51 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/HarnessSourceEffect.java @@ -13,7 +13,7 @@ public class HarnessSourceEffect extends OneShotEffect { public HarnessSourceEffect() { super(Outcome.AIDontUseIt); - staticText = "Harness {this}. (Once harnessed, its ∞ ability is active.)"; + staticText = "Harness {this}. (Once harnessed, its ∞ ability is active.)"; } protected HarnessSourceEffect(final HarnessSourceEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java index 4a99ba55bd2..76314453b36 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java @@ -6,21 +6,29 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; /** * @author TheElk801 */ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { + private final int position; private final boolean textOwnerOf; public PutOnTopOrBottomLibraryTargetEffect(boolean textOwnerOf) { + this(1, textOwnerOf); + } + + public PutOnTopOrBottomLibraryTargetEffect(int position, boolean textOwnerOf) { super(Outcome.ReturnToHand); + this.position = position; this.textOwnerOf = textOwnerOf; } private PutOnTopOrBottomLibraryTargetEffect(final PutOnTopOrBottomLibraryTargetEffect effect) { super(effect); + this.position = effect.position; this.textOwnerOf = effect.textOwnerOf; } @@ -35,10 +43,14 @@ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { if (player == null) { return false; } + String message = position > 1 ? "into your library " + CardUtil.numberToOrdinalText(position) + " from the top or on the" : "on the top or"; boolean onTop = player.chooseUse( - Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", + Outcome.Detriment, "Put the targeted object " + message + " bottom of your library?", null, "Top", "Bottom", source, game ); + if (onTop && position > 1) { + return new PutIntoLibraryNFromTopTargetEffect(position).apply(game, source); + } return new PutOnLibraryTargetEffect(onTop).apply(game, source); } @@ -47,8 +59,23 @@ public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } + StringBuilder sb = new StringBuilder(); String targetText = getTargetPointer().describeTargets(mode.getTargets(), "that permanent"); - return (textOwnerOf ? "the owner of " + targetText : targetText + "'s owner") + - " puts it on their choice of the top or bottom of their library"; + if (textOwnerOf) { + sb.append("the owner of "); + sb.append(targetText); + } else { + sb.append(targetText); + sb.append("'s owner"); + } + sb.append(" puts it "); + if (position > 1) { + sb.append("into their library "); + sb.append(CardUtil.numberToOrdinalText(position)); + sb.append(" from the top or on the bottom"); + } else { + sb.append("on their choice of the top or bottom of their library"); + } + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java index 87875eb4962..6e5cbb61c2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java @@ -3,7 +3,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.cards.ModalDoubleFacedCard; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -37,10 +36,6 @@ public class ReturnToHandAttachedEffect extends OneShotEffect { return false; } Card card = permanent.getMainCard(); - // TODO: Once MDFC ZCC increments are fixed properly, can remove this special case. For now must allow so effect works. - if (permanent.getZoneChangeCounter(game) + 1 != card.getZoneChangeCounter(game) && !(card instanceof ModalDoubleFacedCard)) { - return false; - } return player.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java new file mode 100644 index 00000000000..a7d598bf893 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/RoomCharacteristicsEffect.java @@ -0,0 +1,215 @@ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Abilities; +import mage.abilities.AbilitiesImpl; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.RoomUnlockAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.Card; +import mage.cards.SplitCard; +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.game.permanent.PermanentCard; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * Continuous effect that sets the name and mana value of a Room permanent based + * on its unlocked halves. + * Functions as a characteristic-defining ability. + * 709.5. Some split cards are permanent cards with a single shared type line. + * A shared type line on such an object represents two static abilities that + * function on the battlefield. + * These are "As long as this permanent doesn't have the 'left half unlocked' + * designation, it doesn't have the name, mana cost, or rules text of this + * object's left half" + * and "As long as this permanent doesn't have the 'right half unlocked' + * designation, it doesn't have the name, mana cost, or rules text of this + * object's right half." + * These abilities, as well as which half of that permanent a characteristic is + * in, are part of that object's copiable values. + * @author oscscull + */ +public class RoomCharacteristicsEffect extends ContinuousEffectImpl { + + + public RoomCharacteristicsEffect() { + super(Duration.WhileOnBattlefield, Layer.TextChangingEffects_3, SubLayer.NA, + Outcome.Neutral); + staticText = ""; + } + + private RoomCharacteristicsEffect(final RoomCharacteristicsEffect effect) { + super(effect); + } + + @Override + public RoomCharacteristicsEffect copy() { + return new RoomCharacteristicsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + + if (permanent == null) { + return false; + } + + return removeCharacteristics(game, permanent); + } + + public boolean removeCharacteristics(Game game, Permanent permanent) { + Card roomCardBlueprint = getCard(permanent); + + if (!(roomCardBlueprint instanceof SplitCard)) { + return false; + } + + SplitCard roomCard = (SplitCard) roomCardBlueprint; + + // Remove the name based on unlocked halves + String newName = permanent.getName(); + + boolean isLeftUnlocked = permanent.isLeftDoorUnlocked(); + if (!isLeftUnlocked && roomCard.getLeftHalfCard() != null) { + newName = newName.replace(roomCard.getLeftHalfCard().getName() + " // ", ""); + } + + boolean isRightUnlocked = permanent.isRightDoorUnlocked(); + if (!isRightUnlocked && roomCard.getRightHalfCard() != null) { + newName = newName + .replace(" // " + roomCard.getRightHalfCard().getName(), "") + .replace(roomCard.getRightHalfCard().getName(), ""); + } + + permanent.setName(newName); + + // Set the mana value based on unlocked halves + // Create a new Mana object to accumulate the costs + SpellAbility roomCardSpellAbility = roomCard.getSpellAbility().copy(); + // Remove the mana from the left half's cost to our total Mana object + if (!isLeftUnlocked) { + ManaCosts leftHalfManaCost = null; + if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getSpellAbility() != null) { + leftHalfManaCost = roomCard.getLeftHalfCard().getSpellAbility().getManaCosts(); + } + if (leftHalfManaCost != null) { + CardUtil.adjustCost(roomCardSpellAbility, leftHalfManaCost, true); + } + } + + // Remove the mana from the right half's cost to our total Mana object + if (!isRightUnlocked) { + ManaCosts rightHalfManaCost = null; + if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getSpellAbility() != null) { + rightHalfManaCost = roomCard.getRightHalfCard().getSpellAbility().getManaCosts(); + } + if (rightHalfManaCost != null) { + CardUtil.adjustCost(roomCardSpellAbility, rightHalfManaCost, true); + } + } + + ManaCosts roomCardManaCosts = roomCardSpellAbility.getManaCostsToPay(); + if (roomCardManaCosts.getText().equals("{0}")) { + roomCardManaCosts = new ManaCostsImpl<>(); + } + permanent.setManaCost(roomCardManaCosts); + + + // Remove abilities from locked halves and add unlock abilities + Abilities removedLeftAbilities = new AbilitiesImpl<>(); + Abilities removedRightAbilities = new AbilitiesImpl<>(); + Card abilitySource = permanent; + if (permanent.isCopy()) { + abilitySource = (Card) permanent.getCopyFrom(); + } + for (Ability ability : abilitySource.getAbilities(game)) { + if (!isLeftUnlocked) { + if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getAbilities().contains(ability)) { + if (!removedLeftAbilities.contains(ability)) { + removedLeftAbilities.add(ability); + } + permanent.removeAbility(ability, null, game); + continue; + } + } + if (!isRightUnlocked) { + if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getAbilities().contains(ability)) { + if (!removedRightAbilities.contains(ability)) { + removedRightAbilities.add(ability); + } + permanent.removeAbility(ability, null, game); + } + } + } + // Add the Special Action to unlock doors. + // These will ONLY be active if the corresponding half is LOCKED! + if (!removedLeftAbilities.isEmpty()) { + RoomUnlockAbility leftUnlockAbility = new RoomUnlockAbility(roomCard.getLeftHalfCard().getManaCost(), true); + permanent.addAbility(leftUnlockAbility, roomCard.getLeftHalfCard().getId(), game); + } + if (!removedRightAbilities.isEmpty()) { + RoomUnlockAbility rightUnlockAbility = new RoomUnlockAbility(roomCard.getRightHalfCard().getManaCost(), false); + permanent.addAbility(rightUnlockAbility, roomCard.getRightHalfCard().getId(), game); + } + return true; + } + + private static Card getCard(Permanent permanent) { + Card roomCardBlueprint; + + // Handle copies + if (permanent.isCopy()) { + MageObject copiedObject = permanent.getCopyFrom(); + if (copiedObject instanceof PermanentCard) { + roomCardBlueprint = ((PermanentCard) copiedObject).getCard(); + } else if (copiedObject instanceof Card) { + roomCardBlueprint = (Card) copiedObject; + } else { + roomCardBlueprint = permanent.getMainCard(); + } + } else { + roomCardBlueprint = permanent.getMainCard(); + } + return roomCardBlueprint; + } + + public void restoreUnlockedStats(Game game, Permanent permanent) { + // remove unlock abilities + for (Ability ability : permanent.getAbilities(game)) { + if (ability instanceof RoomUnlockAbility) { + if (((RoomUnlockAbility) ability).isLeftHalf() && permanent.isLeftDoorUnlocked()) { + permanent.removeAbility(ability, null, game); + } else if (!((RoomUnlockAbility) ability).isLeftHalf() && permanent.isRightDoorUnlocked()) { + permanent.removeAbility(ability, null, game); + } + } + } + // restore removed abilities + // copies need abilities to be added back to game state for triggers + SplitCard roomCard = (SplitCard) getCard(permanent); + UUID sourceId = permanent.isCopy() ? permanent.getId() : null; + Game gameParam = permanent.isCopy() ? game : null; + if (permanent.isLeftDoorUnlocked()) { + for (Ability ability : roomCard.getLeftHalfCard().getAbilities()) { + permanent.addAbility(ability, sourceId, gameParam, true); + } + } + if (permanent.isRightDoorUnlocked()) { + for (Ability ability : roomCard.getRightHalfCard().getAbilities()) { + permanent.addAbility(ability, sourceId, gameParam, true); + } + } + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/TargetsDamageTargetsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TargetsDamageTargetsEffect.java index cad1c21c75b..577b5b508dc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TargetsDamageTargetsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TargetsDamageTargetsEffect.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.ArrayList; import java.util.List; @@ -42,37 +41,26 @@ public class TargetsDamageTargetsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (source.getTargets().size() < 2) { - return false; - } - - Target damageTarget = source.getTargets().getByTag(1); - Target additionalDamageTarget = source.getTargets().getByTag(2); - Target destTarget = source.getTargets().getByTag(3); - List damagingPermanents = new ArrayList<>(); List receivingPermanents = new ArrayList<>(); - for (UUID id : damageTarget.getTargets()) { + for (UUID id : source.getTargets().getTargetsByTag(1)) { // dealing damage Permanent permanent = game.getPermanent(id); if (permanent != null) { damagingPermanents.add(permanent); } } - if (additionalDamageTarget != null) { - for (UUID id : additionalDamageTarget.getTargets()) { - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - damagingPermanents.add(permanent); - } + for (UUID id : source.getTargets().getTargetsByTag(2)) { // additional dealing damage, if applicable + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + damagingPermanents.add(permanent); } } - for (UUID id : destTarget.getTargets()) { + for (UUID id : source.getTargets().getTargetsByTag(3)) { // receiving damage Permanent permanent = game.getPermanent(id); if (permanent != null) { receivingPermanents.add(permanent); } } - if (receivingPermanents.isEmpty() || damagingPermanents.isEmpty()) { return false; } @@ -86,6 +74,10 @@ public class TargetsDamageTargetsEffect extends OneShotEffect { @Override public String getText(Mode mode) { + // verify check that target tags are properly setup + if (mode.getTargets().getByTag(1) == null || mode.getTargets().getByTag(3) == null) { + throw new IllegalArgumentException("Wrong code usage: need to add tags to targets"); + } if (staticText != null && !staticText.isEmpty()) { return staticText; } @@ -102,4 +94,4 @@ public class TargetsDamageTargetsEffect extends OneShotEffect { sb.append(mode.getTargets().getByTag(3).getDescription()); return sb.toString(); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAloneSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAloneSourceEffect.java new file mode 100644 index 00000000000..3028a85af92 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAloneSourceEffect.java @@ -0,0 +1,42 @@ +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; +import mage.filter.common.FilterBlockingCreature; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author LevelX2 + */ +public class CantBlockAloneSourceEffect extends RestrictionEffect { + + private static final FilterBlockingCreature filter = new FilterBlockingCreature("Blocking creatures"); + public CantBlockAloneSourceEffect() { + super(Duration.WhileOnBattlefield); + staticText = "{this} can't block alone"; + } + + protected CantBlockAloneSourceEffect(final CantBlockAloneSourceEffect effect) { + super(effect); + } + + @Override + public CantBlockAloneSourceEffect copy() { + return new CantBlockAloneSourceEffect(this); + } + + @Override + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + if (permanent.getId().equals(source.getSourceId())) { + return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).size() <= 1; + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesAllBasicsControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesAllBasicsControlledEffect.java index 1e96acf7468..6b61f21586c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesAllBasicsControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesAllBasicsControlledEffect.java @@ -1,5 +1,6 @@ package mage.abilities.effects.common.continuous; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.mana.*; @@ -8,6 +9,8 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Iterator; + /** * @author TheElk801 */ @@ -21,9 +24,9 @@ public class BecomesAllBasicsControlledEffect extends ContinuousEffectImpl { new GreenManaAbility() }; - public BecomesAllBasicsControlledEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); - this.staticText = "Lands you control are every basic land type in addition to their other types"; + public BecomesAllBasicsControlledEffect(Duration duration) { + super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); + this.staticText = "lands you control are every basic land type in addition to their other types"; dependendToTypes.add(DependencyType.BecomeNonbasicLand); dependencyTypes.add(DependencyType.BecomeMountain); dependencyTypes.add(DependencyType.BecomeForest); @@ -42,29 +45,55 @@ public class BecomesAllBasicsControlledEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), game)) { - permanent.addSubType(game, - SubType.PLAINS, - SubType.ISLAND, - SubType.SWAMP, - SubType.MOUNTAIN, - SubType.FOREST); - // Optimization: Remove basic mana abilities since they are redundant with AnyColorManaAbility - // and keeping them will only produce too many combinations inside ManaOptions - for (Ability basicManaAbility : basicManaAbilities) { - if (permanent.getAbilities(game).containsRule(basicManaAbility)) { - permanent.removeAbility(basicManaAbility, source.getSourceId(), game); - } + public void init(Ability source, Game game) { + super.init(source, game); + if (getAffectedObjectsSet()) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), game)) { + affectedObjectList.add(new MageObjectReference(permanent, game)); } - // Add the {T}: Add one mana of any color ability - // This is functionally equivalent to having five "{T}: Add {COLOR}" for each COLOR in {W}{U}{B}{R}{G} - AnyColorManaAbility ability = new AnyColorManaAbility(); - if (!permanent.getAbilities(game).containsRule(ability)) { - permanent.addAbility(ability, source.getSourceId(), game); + } + } + + @Override + public boolean apply(Game game, Ability source) { + if (!getAffectedObjectsSet()) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), game + )) { + removeTypes(permanent, game, source); + } + return true; + } + for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { + Permanent permanent = it.next().getPermanent(game); + if (permanent != null) { + removeTypes(permanent, game, source); + } else { + it.remove(); } } return true; } + + private static void removeTypes(Permanent permanent, Game game, Ability source) { + permanent.addSubType(game, + SubType.PLAINS, + SubType.ISLAND, + SubType.SWAMP, + SubType.MOUNTAIN, + SubType.FOREST); + // Optimization: Remove basic mana abilities since they are redundant with AnyColorManaAbility + // and keeping them will only produce too many combinations inside ManaOptions + for (Ability basicManaAbility : basicManaAbilities) { + if (permanent.getAbilities(game).containsRule(basicManaAbility)) { + permanent.removeAbility(basicManaAbility, source.getSourceId(), game); + } + } + // Add the {T}: Add one mana of any color ability + // This is functionally equivalent to having five "{T}: Add {COLOR}" for each COLOR in {W}{U}{B}{R}{G} + AnyColorManaAbility ability = new AnyColorManaAbility(); + if (!permanent.getAbilities(game).containsRule(ability)) { + permanent.addAbility(ability, source.getSourceId(), game); + } + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java index 099abc9d1ac..e6e00c1372c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureEffect.java @@ -16,7 +16,7 @@ import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.WardAbility; import mage.cards.Card; import mage.cards.CardImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.cards.repository.TokenInfo; import mage.cards.repository.TokenRepository; import mage.constants.*; @@ -375,9 +375,9 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl { // it can't transform. If the front face of the card is a creature card, you can turn it face up by paying // its mana cost. If you do, its front face will be up. - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { // only MDFC uses independent card sides on 2024 - return ((ModalDoubleFacedCard) card).getLeftHalfCard(); + return ((DoubleFacedCard) card).getLeftHalfCard(); } else { return card; } 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 c1db549eaaf..36537f5a62b 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 @@ -116,7 +116,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl { StringBuilder sb = new StringBuilder(); String message = filter.getMessage().toLowerCase(Locale.ENGLISH); boolean each = message.startsWith("each"); - if (excludeSource && !each && !message.startsWith("all")) { + if (excludeSource && !each && !message.startsWith("all ")) { sb.append("other "); } sb.append(filter.getMessage()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java index 75102356986..3c84cdc6ae4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityWithAttachmentEffect.java @@ -122,7 +122,7 @@ public class GainAbilityWithAttachmentEffect extends ContinuousEffectImpl { } ability.addCost(cost.copy()); } - if (source != null && game != null) { + if (source != null && game != null && useAttachedCost != null) { ability.addCost(useAttachedCost.copy().setMageObjectReference(source, game)); } if (consumer != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/NonbasicLandsAreMountainsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/NonbasicLandsAreMountainsEffect.java new file mode 100644 index 00000000000..0136982dbb9 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/NonbasicLandsAreMountainsEffect.java @@ -0,0 +1,45 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.RedManaAbility; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author LevelX2 + */ +public class NonbasicLandsAreMountainsEffect extends ContinuousEffectImpl { + + public NonbasicLandsAreMountainsEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); + this.staticText = "nonbasic lands are Mountains"; + this.dependencyTypes.add(DependencyType.BecomeMountain); + this.dependendToTypes.add(DependencyType.BecomeNonbasicLand); + } + + private NonbasicLandsAreMountainsEffect(final NonbasicLandsAreMountainsEffect effect) { + super(effect); + } + + @Override + public NonbasicLandsAreMountainsEffect copy() { + return new NonbasicLandsAreMountainsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent land : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LANDS_NONBASIC, source.getControllerId(), game)) { + // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects + // So the ability removing has to be done before Layer 6 + // Lands have their mana ability intrinsically, so that is added in layer 4 + land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType); + land.addSubType(game, SubType.MOUNTAIN); + land.removeAllAbilities(source.getSourceId(), game); + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetBasePowerToughnessAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetBasePowerToughnessAllEffect.java index 5b852371644..ebb364b2a70 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetBasePowerToughnessAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetBasePowerToughnessAllEffect.java @@ -34,6 +34,10 @@ public class SetBasePowerToughnessAllEffect extends ContinuousEffectImpl { this(StaticValue.get(power), StaticValue.get(toughness), duration, filter); } + public SetBasePowerToughnessAllEffect(DynamicValue stats, Duration duration, FilterPermanent filter) { + this(stats, stats, duration, filter); + } + public SetBasePowerToughnessAllEffect(DynamicValue power, DynamicValue toughness, Duration duration, FilterPermanent filter) { super(duration, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); this.power = power; diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java index 2646319f1da..1f3afd4589e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/YouDontLoseManaEffect.java @@ -14,8 +14,13 @@ public class YouDontLoseManaEffect extends ContinuousEffectImpl { private final ManaType manaType; public YouDontLoseManaEffect(ManaType manaType) { - super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); - staticText = "you don't lose unspent " + manaType + " mana as steps and phases end"; + this(Duration.WhileOnBattlefield, manaType); + } + + public YouDontLoseManaEffect(Duration duration, ManaType manaType) { + super(duration, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); + staticText = (duration == Duration.EndOfTurn ? "until end of turn, " : "") + + "you don't lose unspent " + manaType + " mana as steps and phases end"; this.manaType = manaType; } @@ -37,4 +42,4 @@ public class YouDontLoseManaEffect extends ContinuousEffectImpl { } return false; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java new file mode 100644 index 00000000000..7d3ddde1d98 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryForFourDifferentCardsEffect.java @@ -0,0 +1,92 @@ +package mage.abilities.effects.common.search; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.PutCards; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; +import mage.target.common.TargetOpponent; + +/** + * @author TheElk801 + */ +public class SearchLibraryForFourDifferentCardsEffect extends OneShotEffect { + + private final FilterCard filter; + private final PutCards putCards; + private final boolean useTargetPointer; + private static final FilterCard filter2 = new FilterCard("cards to put in graveyard"); + + public SearchLibraryForFourDifferentCardsEffect(FilterCard filter, PutCards putCards, boolean useTargetPointer) { + super(Outcome.Benefit); + this.filter = filter; + this.putCards = putCards; + this.useTargetPointer = useTargetPointer; + staticText = "search your library for up to four " + filter + + " with different names and reveal them. " + (useTargetPointer ? "Target" : "An") + + " opponent chooses two of those cards. Put the chosen cards into your graveyard and the rest " + + putCards.getMessage(false, false) + ". Then shuffle"; + } + + private SearchLibraryForFourDifferentCardsEffect(final SearchLibraryForFourDifferentCardsEffect effect) { + super(effect); + this.filter = effect.filter; + this.putCards = effect.putCards; + this.useTargetPointer = effect.useTargetPointer; + } + + @Override + public SearchLibraryForFourDifferentCardsEffect copy() { + return new SearchLibraryForFourDifferentCardsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCardInLibrary targetCards = new TargetCardWithDifferentNameInLibrary(0, 4, filter); + player.searchLibrary(targetCards, source, game); + Cards cards = new CardsImpl(targetCards.getTargets()); + cards.retainZone(Zone.LIBRARY, game); + player.revealCards(source, cards, game); + if (cards.isEmpty()) { + player.shuffleLibrary(source, game); + return true; + } + + Cards toGrave = new CardsImpl(); + if (cards.size() > 2) { + Player opponent; + if (useTargetPointer) { + opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + } else { + TargetPlayer target = new TargetOpponent(true); + player.choose(outcome, target, source, game); + opponent = game.getPlayer(target.getFirstTarget()); + } + if (opponent != null) { + TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, filter2); + opponent.choose(Outcome.Discard, cards, targetDiscard, source, game); + toGrave.addAll(targetDiscard.getTargets()); + } + } else { + toGrave.addAll(cards); + } + cards.removeAll(toGrave); + player.moveCards(toGrave, Zone.GRAVEYARD, source, game); + putCards.moveCards(player, cards, source, game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AirbendTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AirbendTargetEffect.java index b98f6b35221..dace0a8893e 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/AirbendTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AirbendTargetEffect.java @@ -17,11 +17,11 @@ import mage.constants.Outcome; 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.Objects; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -47,18 +47,21 @@ public class AirbendTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Set permanents = this + if (player == null) { + return false; + } + Set objects = this .getTargetPointer() .getTargets(game, source) .stream() - .map(game::getPermanent) + .map(uuid -> Optional.ofNullable((Card) game.getPermanent(uuid)).orElseGet(() -> game.getSpell(uuid))) .filter(Objects::nonNull) .collect(Collectors.toSet()); - if (player == null || permanents.isEmpty()) { + if (objects.isEmpty()) { return false; } - player.moveCards(permanents, Zone.EXILED, source, game); - Cards cards = new CardsImpl(permanents); + player.moveCards(objects, Zone.EXILED, source, game); + Cards cards = new CardsImpl(objects); cards.retainZone(Zone.EXILED, game); for (Card card : cards.getCards(game)) { game.addEffect(new AirbendingCastEffect(card, game), source); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/BlightControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/BlightControllerEffect.java new file mode 100644 index 00000000000..05dd095a522 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/BlightControllerEffect.java @@ -0,0 +1,59 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +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.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * @author TheElk801 + */ +public class BlightControllerEffect extends OneShotEffect { + + private final int amount; + + public BlightControllerEffect(int amount) { + super(Outcome.Detriment); + this.amount = amount; + staticText = "blight " + amount; + } + + private BlightControllerEffect(final BlightControllerEffect effect) { + super(effect); + this.amount = effect.amount; + } + + @Override + public BlightControllerEffect copy() { + return new BlightControllerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + return doBlight(player, amount, game, source) != null; + } + + public static Permanent doBlight(Player player, int amount, Game game, Ability source) { + if (player == null || amount < 1 || !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game, 1 + )) { + return null; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.withNotTarget(true); + target.withChooseHint("to put a -1/-1 counter on"); + player.choose(Outcome.UnboostCreature, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(CounterType.M1M1.createInstance(amount), source, game); + } + return permanent; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java index 9982a5dc7fc..6f7da3fb18b 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/EarthbendTargetEffect.java @@ -4,6 +4,8 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; @@ -25,16 +27,27 @@ import mage.util.CardUtil; */ public class EarthbendTargetEffect extends OneShotEffect { - private final int amount; + private final DynamicValue amount; + private final boolean withReminderText; public EarthbendTargetEffect(int amount) { + this(amount, true); + } + + public EarthbendTargetEffect(int amount, boolean withReminderText) { + this(StaticValue.get(amount), withReminderText); + } + + public EarthbendTargetEffect(DynamicValue amount, boolean withReminderText) { super(Outcome.Benefit); this.amount = amount; + this.withReminderText = withReminderText; } private EarthbendTargetEffect(final EarthbendTargetEffect effect) { super(effect); this.amount = effect.amount; + this.withReminderText = effect.withReminderText; } @Override @@ -48,18 +61,25 @@ public class EarthbendTargetEffect extends OneShotEffect { if (permanent == null) { return false; } + int value = amount.calculate(game, source, this); + doEarthBend(permanent, value, game, source); + return true; + } + + public static void doEarthBend(Permanent permanent, int value, Game game, Ability source) { game.addEffect(new BecomesCreatureTargetEffect( new CreatureToken(0, 0) .withAbility(HasteAbility.getInstance()), false, true, Duration.Custom ), source); - permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game); + // Make the land into a creature before putting counters on, for the purposes of counter doublers that only apply to creatures. + game.processAction(); + permanent.addCounters(CounterType.P1P1.createInstance(value), source, game); game.addDelayedTriggeredAbility(new EarthbendingDelayedTriggeredAbility(permanent, game), source); game.fireEvent(GameEvent.getEvent( GameEvent.EventType.EARTHBENDED, permanent.getId(), - source, source.getControllerId(), amount + source, source.getControllerId(), value )); - return true; } @Override @@ -67,10 +87,25 @@ public class EarthbendTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "earthbend " + amount + ". (Target land you control becomes a 0/0 creature " + - "with haste that's still a land. Put " + CardUtil.numberToText(amount, "a") + - " +1/+1 counter" + (amount > 1 ? "s" : "") + " on it. " + - "When it dies or is exiled, return it to the battlefield tapped.)"; + StringBuilder sb = new StringBuilder("earthbend "); + if (amount instanceof StaticValue) { + sb.append(amount); + } else { + sb.append("X, where X is "); + sb.append(amount.getMessage()); + } + if (!withReminderText) { + return sb.toString(); + } + sb.append(". (Target land you control becomes a 0/0 creature with haste that's still a land. Put "); + String value = amount instanceof StaticValue + ? CardUtil.numberToText(((StaticValue) amount).getValue(), "a") + : amount.toString(); + sb.append(value); + sb.append(" +1/+1 counter"); + sb.append(("a".equals(value) ? "" : "s")); + sb.append(" on it. When it dies or is exiled, return it to the battlefield tapped.)"); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java index 08b39d74c6d..603228ccf48 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ManifestDreadEffect.java @@ -7,25 +7,39 @@ import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; +import mage.counters.Counter; import mage.game.Game; import mage.game.events.ManifestedDreadEvent; 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.ArrayList; +import java.util.List; +import java.util.stream.Collectors; /** * @author TheElk801 */ public class ManifestDreadEffect extends OneShotEffect { - public ManifestDreadEffect() { + private final List counters = new ArrayList<>(); + + public ManifestDreadEffect(Counter... counters) { super(Outcome.Benefit); - staticText = "manifest dread"; + for (Counter counter : counters) { + this.counters.add(counter); + } + staticText = this.makeText(); } private ManifestDreadEffect(final ManifestDreadEffect effect) { super(effect); + for (Counter counter : effect.counters) { + this.counters.add(counter.copy()); + } } @Override @@ -36,7 +50,17 @@ public class ManifestDreadEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - return player != null && doManifestDread(player, source, game) != null; + if (player == null) { + return false; + } + Permanent permanent = doManifestDread(player, source, game); + if (permanent == null) { + return true; + } + for (Counter counter : counters) { + permanent.addCounters(counter, source, game); + } + return true; } public static Permanent doManifestDread(Player player, Ability source, Game game) { @@ -70,4 +94,15 @@ public class ManifestDreadEffect extends OneShotEffect { game.fireEvent(new ManifestedDreadEvent(permanent, source, player.getId(), cards, game)); return permanent; } + + private String makeText() { + StringBuilder sb = new StringBuilder("manifest dread"); + if (this.counters.isEmpty()) { + return sb.toString(); + } + sb.append(", then put "); + sb.append(CardUtil.concatWithAnd(counters.stream().map(Counter::getDescription).collect(Collectors.toList()))); + sb.append(" on that creature"); + return sb.toString(); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java index 634b2da4d30..ee17ef00cea 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ScryTargetEffect.java @@ -8,7 +8,6 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -57,7 +56,7 @@ public class ScryTargetEffect extends OneShotEffect { } StringBuilder sb = new StringBuilder(getTargetPointer().describeTargets(mode.getTargets(), "that player")); sb.append(" scries "); - sb.append(CardUtil.numberToText(amount.toString())); + sb.append(amount.toString()); return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java b/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java deleted file mode 100644 index 5786ddfe5d3..00000000000 --- a/Mage/src/main/java/mage/abilities/hint/common/PermanentsSacrificedThisTurnHint.java +++ /dev/null @@ -1,28 +0,0 @@ -package mage.abilities.hint.common; - -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.PermanentsSacrificedThisTurnCount; -import mage.abilities.hint.Hint; -import mage.abilities.hint.ValueHint; -import mage.game.Game; - -/** - * @author Susucr - */ -public enum PermanentsSacrificedThisTurnHint implements Hint { - instance; - - private static final Hint hint = new ValueHint( - "Permanents sacrificed this turn", PermanentsSacrificedThisTurnCount.instance - ); - - @Override - public String getText(Game game, Ability ability) { - return hint.getText(game, ability); - } - - @Override - public PermanentsSacrificedThisTurnHint copy() { - return this; - } -} diff --git a/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java b/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java deleted file mode 100644 index cb225680b6f..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/CantAttackAloneAbility.java +++ /dev/null @@ -1,26 +0,0 @@ - -package mage.abilities.keyword; - -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; -import mage.constants.Zone; - -/** - * @author magenoxx_at_googlemail.com - */ -public class CantAttackAloneAbility extends SimpleStaticAbility { - - public CantAttackAloneAbility() { - super(Zone.BATTLEFIELD, new CantAttackAloneSourceEffect()); - } - - private CantAttackAloneAbility(CantAttackAloneAbility ability) { - super(ability); - } - - @Override - public CantAttackAloneAbility copy() { - return new CantAttackAloneAbility(this); - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/CantAttackOrBlockAloneAbility.java b/Mage/src/main/java/mage/abilities/keyword/CantAttackOrBlockAloneAbility.java new file mode 100644 index 00000000000..4b9dd9feab8 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/CantAttackOrBlockAloneAbility.java @@ -0,0 +1,29 @@ + + +package mage.abilities.keyword; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CantAttackAloneSourceEffect; +import mage.abilities.effects.common.combat.CantBlockAloneSourceEffect; +import mage.constants.Zone; + +/** + * @author notgreat + */ +public class CantAttackOrBlockAloneAbility extends SimpleStaticAbility { + + public CantAttackOrBlockAloneAbility() { + super(Zone.BATTLEFIELD, new CantAttackAloneSourceEffect().setText("{this} can't attack or block alone")); + this.addEffect(new CantBlockAloneSourceEffect().setText("")); + } + + private CantAttackOrBlockAloneAbility(CantAttackOrBlockAloneAbility ability) { + super(ability); + } + + @Override + public CantAttackOrBlockAloneAbility copy() { + return new CantAttackOrBlockAloneAbility(this); + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/CantBlockAloneAbility.java b/Mage/src/main/java/mage/abilities/keyword/CantBlockAloneAbility.java deleted file mode 100644 index 62e64e4948d..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/CantBlockAloneAbility.java +++ /dev/null @@ -1,40 +0,0 @@ - - -package mage.abilities.keyword; - -import mage.constants.Zone; -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; - -import java.io.ObjectStreamException; - -/** - * @author magenoxx_at_googlemail.com - */ -public class CantBlockAloneAbility extends StaticAbility implements MageSingleton { - - private static final CantBlockAloneAbility instance = new CantBlockAloneAbility(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static CantBlockAloneAbility getInstance() { - return instance; - } - - private CantBlockAloneAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "{this} can't block alone."; - } - - @Override - public CantBlockAloneAbility copy() { - return instance; - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java index 70f36cad717..ca871fbffed 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CraftAbility.java @@ -121,7 +121,8 @@ class CraftCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Card sourceCard = game.getCard(source.getSourceId()); + if (player == null || sourceCard == null) { paid = false; return paid; } @@ -142,7 +143,7 @@ class CraftCost extends CostImpl { .collect(Collectors.toSet()); player.moveCardsToExile( cards, source, game, true, - CardUtil.getExileZoneId(game, source), + CardUtil.getExileZoneId(game, sourceCard.getMainCard().getId(), sourceCard.getMainCard().getZoneChangeCounter(game)), CardUtil.getSourceName(game, source) ); paid = true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java index 421a25858d3..c033bc5e8b5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java @@ -300,6 +300,7 @@ class ForetellAddCostEffect extends ContinuousEffectImpl { if (game.getState().getZone(mainCardId) == Zone.EXILED) { String foretellCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Cost"); String foretellSplitCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Split Cost"); + // TODO: clean this up if (card instanceof SplitCard) { if (foretellCost != null) { SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard(); @@ -363,6 +364,14 @@ class ForetellAddCostEffect extends ContinuousEffectImpl { ability.setAbilityName(spellCard.getName()); game.getState().addOtherAbility(spellCard, ability); } + } else if (card instanceof TransformingDoubleFacedCard && foretellCost != null) { + Card frontCard = ((TransformingDoubleFacedCard) card).getLeftHalfCard(); + ForetellCostAbility ability = new ForetellCostAbility(foretellCost); + ability.setSourceId(frontCard.getId()); + ability.setControllerId(source.getControllerId()); + ability.setSpellAbilityType(frontCard.getSpellAbility().getSpellAbilityType()); + ability.setAbilityName(frontCard.getName()); + game.getState().addOtherAbility(frontCard, ability); } else if (foretellCost != null) { ForetellCostAbility ability = new ForetellCostAbility(foretellCost); ability.setSourceId(card.getId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/MayhemLandAbility.java b/Mage/src/main/java/mage/abilities/keyword/MayhemLandAbility.java index 14c5d962023..064028ae4d0 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MayhemLandAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MayhemLandAbility.java @@ -1,23 +1,22 @@ package mage.abilities.keyword; -import mage.MageIdentifier; -import mage.abilities.PlayLandAbility; -import mage.cards.Card; -import mage.constants.Zone; +import mage.abilities.Ability; +import mage.abilities.StaticAbility; +import mage.abilities.effects.AsThoughEffect; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.constants.*; import mage.game.Game; -import java.util.Set; import java.util.UUID; -public class MayhemLandAbility extends PlayLandAbility { +public class MayhemLandAbility extends StaticAbility { private final String rule; - public MayhemLandAbility(Card card) { - super(card.getName()); - this.zone = Zone.GRAVEYARD; + public MayhemLandAbility() { + super(AbilityType.STATIC, Zone.GRAVEYARD); this.newId(); - this.name += " with Mayhem"; + this.addEffect(new MayhemPlayEffect()); this.addWatcher(new MayhemWatcher()); this.setRuleAtTheTop(true); this.rule = "Mayhem " + @@ -30,24 +29,6 @@ public class MayhemLandAbility extends PlayLandAbility { this.rule = ability.rule; } - @Override - public ActivationStatus canActivate(UUID playerId, Game game) { - if (!Zone.GRAVEYARD.match(game.getState().getZone(getSourceId())) - || !MayhemWatcher.checkCard(getSourceId(), game)) { - return ActivationStatus.getFalse(); - } - return super.canActivate(playerId, game); - } - - @Override - public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { - if (!super.activate(game, allowedIdentifiers, noMana)) { - return false; - } - this.setCostsTag(MayhemAbility.MAYHEM_ACTIVATION_VALUE_KEY, null); - return true; - } - @Override public MayhemLandAbility copy() { return new MayhemLandAbility(this); @@ -57,4 +38,31 @@ public class MayhemLandAbility extends PlayLandAbility { public String getRule() { return rule; } - } \ No newline at end of file +} + +class MayhemPlayEffect extends AsThoughEffectImpl { + + public MayhemPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileInGraveyard, Outcome.Neutral); + } + + public MayhemPlayEffect(final MayhemPlayEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return Zone.GRAVEYARD.match(game.getState().getZone(sourceId)) + && MayhemWatcher.checkCard(sourceId, game); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public AsThoughEffect copy() { + return new MayhemPlayEffect(this); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java b/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java deleted file mode 100644 index 222f6b65511..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.abilities.keyword; - -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; -import mage.constants.Zone; - -import java.io.ObjectStreamException; - -/** - * @author LevelX2 - */ -public class PartnerFatherAndSonAbility extends StaticAbility implements MageSingleton { - - private static final PartnerFatherAndSonAbility instance = new PartnerFatherAndSonAbility(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static PartnerFatherAndSonAbility getInstance() { - return instance; - } - - private PartnerFatherAndSonAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "Partner—Father & son (You can have two commanders if both have this ability.)"; - } - - @Override - public PartnerFatherAndSonAbility copy() { - return instance; - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java b/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java deleted file mode 100644 index 9693819ff8d..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.abilities.keyword; - -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; -import mage.constants.Zone; - -import java.io.ObjectStreamException; - -/** - * @author LevelX2 - */ -public class PartnerSurvivorsAbility extends StaticAbility implements MageSingleton { - - private static final PartnerSurvivorsAbility instance = new PartnerSurvivorsAbility(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static PartnerSurvivorsAbility getInstance() { - return instance; - } - - private PartnerSurvivorsAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "Partner—Survivors (You can have two commanders if both have this ability.)"; - } - - @Override - public PartnerSurvivorsAbility copy() { - return instance; - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/PowerUpAbility.java b/Mage/src/main/java/mage/abilities/keyword/PowerUpAbility.java new file mode 100644 index 00000000000..7f93014345a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/PowerUpAbility.java @@ -0,0 +1,53 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class PowerUpAbility extends ActivatedAbilityImpl { + + private enum PowerUpAbilityAdjuster implements CostAdjuster { + instance; + + @Override + public void reduceCost(Ability ability, Game game) { + Permanent permanent = ability.getSourcePermanentIfItStillExists(game); + if (permanent != null && permanent.getTurnsOnBattlefield() == 0) { + CardUtil.adjustCost(ability, permanent.getManaCost(), false); + } + } + } + + public PowerUpAbility(Effect effect, Cost cost) { + this(Zone.BATTLEFIELD, effect, cost); + this.maxActivationsPerGame = 1; + this.setCostAdjuster(PowerUpAbilityAdjuster.instance); + } + + public PowerUpAbility(Zone zone, Effect effect, Cost cost) { + super(zone, effect, cost); + } + + private PowerUpAbility(final PowerUpAbility ability) { + super(ability); + } + + @Override + public PowerUpAbility copy() { + return new PowerUpAbility(this); + } + + @Override + public String getRule() { + return "Power-up — " + super.getRule(); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SneakAbility.java b/Mage/src/main/java/mage/abilities/keyword/SneakAbility.java new file mode 100644 index 00000000000..d38089c2278 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/SneakAbility.java @@ -0,0 +1,77 @@ +package mage.abilities.keyword; + +import mage.MageIdentifier; +import mage.abilities.SpellAbility; +import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.PhaseStep; +import mage.constants.SpellAbilityType; +import mage.constants.TimingRule; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.UnblockedPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; + +import java.util.Set; + +/** + * @author TheElk801 + */ +public class SneakAbility extends SpellAbility { + + public static final String SNEAK_ACTIVATION_VALUE_KEY = "sneakActivation"; + private static final FilterControlledPermanent filter = new FilterControlledPermanent("unblocked attacker you control"); + + static { + filter.add(UnblockedPredicate.instance); + filter.add(AttackingPredicate.instance); + } + + public SneakAbility(Card card, String manaString) { + super(card.getSpellAbility()); + this.newId(); + this.setCardName(card.getName() + " with Sneak"); + timing = TimingRule.INSTANT; + zone = Zone.HAND; + spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + + this.clearManaCosts(); + this.clearManaCostsToPay(); + this.addCost(new ManaCostsImpl<>(manaString)); + this.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter))); + + this.setRuleAtTheTop(true); + } + + protected SneakAbility(final SneakAbility ability) { + super(ability); + } + + @Override + public boolean activate(Game game, Set allowedIdentifiers, boolean noMana) { + if (!super.activate(game, allowedIdentifiers, noMana) + || game.getStep().getType() != PhaseStep.DECLARE_BLOCKERS) { + return false; + } + this.setCostsTag(SNEAK_ACTIVATION_VALUE_KEY, null); + return true; + } + + @Override + public SneakAbility copy() { + return new SneakAbility(this); + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("Sneak "); + sb.append(getManaCosts().getText()); + sb.append(" (You may cast this spell for "); + sb.append(getManaCosts().getText()); + sb.append(" if you also return an unblocked attacker you control to hand during the declare blockers step.)"); + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index f69518cf516..47408ef3f6b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -18,7 +18,7 @@ import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.Card; import mage.cards.CardsImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -177,10 +177,10 @@ public class SuspendAbility extends SpecialAction { * or added by Jhoira of the Ghitu */ public static void addSuspendTemporaryToCard(Card card, Ability source, Game game) { - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { // Need to ensure the suspend ability gets put on the left side card // since counters get added to this card. - card = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + card = ((DoubleFacedCard) card).getLeftHalfCard(); } SuspendAbility ability = new SuspendAbility(0, null, card, false); ability.setSourceId(card.getId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java b/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java new file mode 100644 index 00000000000..2ce4dfd4368 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/WaterbendAbility.java @@ -0,0 +1,99 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.StaticAbility; +import mage.abilities.costs.*; +import mage.abilities.costs.common.WaterbendCost; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class WaterbendAbility extends StaticAbility implements OptionalAdditionalSourceCosts { + + private static final String promptString = "Waterbend {"; + private static final String keywordText = "As an additional cost to cast this spell, you may waterbend {"; + private static final String reminderText = "While paying a waterbend cost, you can tap your artifacts and creatures to help. Each one pays for {1}."; + private final String rule; + private final int amount; + + public static final String WATERBEND_ACTIVATION_VALUE_KEY = "waterbendActivation"; + + protected OptionalAdditionalCost additionalCost; + + public static OptionalAdditionalCost makeCost(int amount) { + OptionalAdditionalCost cost = new OptionalAdditionalCostImpl( + keywordText + amount + '}', reminderText, new WaterbendCost(amount) + ); + cost.setRepeatable(false); + return cost; + } + + public WaterbendAbility(int amount) { + this(amount, null); + } + + public WaterbendAbility(int amount, String extraInfoText) { + super(Zone.STACK, null); + this.additionalCost = makeCost(amount); + this.rule = additionalCost.getName() + ". " + (extraInfoText == null ? "" : extraInfoText + ". ") + additionalCost.getReminderText(); + this.setRuleAtTheTop(true); + this.amount = amount; + } + + private WaterbendAbility(final WaterbendAbility ability) { + super(ability); + this.rule = ability.rule; + this.additionalCost = ability.additionalCost.copy(); + this.amount = ability.amount; + } + + @Override + public WaterbendAbility copy() { + return new WaterbendAbility(this); + } + + public void resetCost() { + if (additionalCost != null) { + additionalCost.reset(); + } + } + + @Override + public void addOptionalAdditionalCosts(Ability ability, Game game) { + if (!(ability instanceof SpellAbility)) { + return; + } + + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return; + } + + this.resetCost(); + boolean canPay = additionalCost.canPay(ability, this, ability.getControllerId(), game); + if (!canPay || !player.chooseUse(Outcome.Exile, promptString + amount + "}?", ability, game)) { + return; + } + + additionalCost.activate(); + for (Cost cost : ((Costs) additionalCost)) { + ability.getCosts().add(cost.copy()); + } + ability.setCostsTag(WATERBEND_ACTIVATION_VALUE_KEY, null); + } + + @Override + public String getCastMessageSuffix() { + return additionalCost.getCastSuffixMessage(0); + } + + @Override + public String getRule() { + return rule; + } +} diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 8882c14869d..b78ff8d133a 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -72,6 +73,7 @@ public interface Card extends MageObject, Ownerable { SpellAbility getSecondFaceSpellAbility(); + //TODO: remove after tdfc rework boolean isNightCard(); default boolean meldsWith(Card card) { @@ -156,7 +158,7 @@ public interface Card extends MageObject, Ownerable { void addAbility(Ability ability); - void looseAllAbilities(Game game); + void loseAllAbilities(Game game); boolean addCounters(Counter counter, Ability source, Game game); @@ -250,6 +252,10 @@ public interface Card extends MageObject, Ownerable { List getAttachments(); + void setPT(int power, int toughness); + + void setPT(MageInt power, MageInt toughness); + /** * @param attachment can be any object: card, permanent, token * @param source can be null for default checks like state base diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 90acef7ccce..966363ae338 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.MageInt; import mage.MageObject; import mage.MageObjectImpl; import mage.Mana; @@ -126,6 +127,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card { nightCard = card.nightCard; secondSideCardClazz = card.secondSideCardClazz; secondSideCard = null; // will be set on first getSecondCardFace call if card has one + // TODO: temporary until cards tdfc cards are converted + // can do normal copy after + if (card.secondSideCard instanceof DoubleFacedCardHalf) { + secondSideCard = card.secondSideCard.copy(); + } if (card.secondSideCard instanceof MockableCard) { // workaround to support gui's mock cards secondSideCard = card.secondSideCard.copy(); @@ -297,7 +303,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } @Override - public void looseAllAbilities(Game game) { + public void loseAllAbilities(Game game) { CardState cardState = game.getState().getCardState(this.getId()); cardState.setLostAllAbilities(true); cardState.getAbilities().clear(); @@ -393,6 +399,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card { this.abilities.setControllerId(ownerId); } + @Override + public void setPT(int power, int toughness) { + this.setPT(new MageInt(power), new MageInt(toughness)); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + this.power = power; + this.toughness = toughness; + } + @Override public UUID getControllerOrOwnerId() { return getOwnerId(); @@ -517,13 +534,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } - // handle half of Modal Double Faces Cards on stack - if (stackObject == null && (this instanceof ModalDoubleFacedCard)) { - stackObject = game.getStack().getSpell(((ModalDoubleFacedCard) this).getLeftHalfCard().getId(), + // handle half of Double Faces Cards on stack + if (stackObject == null && (this instanceof DoubleFacedCard)) { + stackObject = game.getStack().getSpell(((DoubleFacedCard) this).getLeftHalfCard().getId(), false); if (stackObject == null) { stackObject = game.getStack() - .getSpell(((ModalDoubleFacedCard) this).getRightHalfCard().getId(), false); + .getSpell(((DoubleFacedCard) this).getRightHalfCard().getId(), false); } } @@ -650,7 +667,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { // If a spell or ability instructs a player to transform a permanent that // isn’t represented by a transforming token or a transforming double-faced // card, nothing happens. - return this.secondSideCardClazz != null || this.nightCard; + return this.secondSideCardClazz != null || this.nightCard || this.secondSideCard != null; } @Override @@ -947,7 +964,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } } - if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){ + if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()) { // Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583 // Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl). canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game); diff --git a/Mage/src/main/java/mage/cards/DoubleFacedCard.java b/Mage/src/main/java/mage/cards/DoubleFacedCard.java new file mode 100644 index 00000000000..f9c752e0d5a --- /dev/null +++ b/Mage/src/main/java/mage/cards/DoubleFacedCard.java @@ -0,0 +1,413 @@ +package mage.cards; + +import mage.MageInt; +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.*; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.constants.*; +import mage.counters.Counter; +import mage.counters.Counters; +import mage.game.Game; +import mage.game.GameState; +import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; +import mage.util.SubTypes; + +import java.util.List; +import java.util.UUID; + +/** + * @author JayDi85 - originally from ModalDoubleFaceCard + */ +public abstract class DoubleFacedCard extends CardImpl implements CardWithHalves { + + protected DoubleFacedCardHalf leftHalfCard; // main card in all zone + protected DoubleFacedCardHalf rightHalfCard; // second side card, can be only in stack and battlefield zones + + protected DoubleFacedCard(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs, SpellAbilityType spellAbilityType) { + super(ownerId, setInfo, cardTypes, costs, spellAbilityType); + } + + public DoubleFacedCard(DoubleFacedCard card) { + super(card); + // make sure all parts created and parent ref added + this.leftHalfCard = (DoubleFacedCardHalf) card.getLeftHalfCard().copy(); + leftHalfCard.setParentCard(this); + this.rightHalfCard = (DoubleFacedCardHalf) card.getRightHalfCard().copy(); + rightHalfCard.setParentCard(this); + } + + public DoubleFacedCardHalf getLeftHalfCard() { + return leftHalfCard; + } + + public DoubleFacedCardHalf getRightHalfCard() { + return leftHalfCard; + } + + public void setParts(DoubleFacedCardHalf leftHalfCard, DoubleFacedCardHalf rightHalfCard) { + // for card copy only - set new parts + this.leftHalfCard = leftHalfCard; + leftHalfCard.setParentCard(this); + this.rightHalfCard = rightHalfCard; + rightHalfCard.setParentCard(this); + } + + @Override + public void assignNewId() { + super.assignNewId(); + leftHalfCard.assignNewId(); + rightHalfCard.assignNewId(); + } + + @Override + public void setCopy(boolean isCopy, MageObject copiedFrom) { + super.setCopy(isCopy, copiedFrom); + leftHalfCard.setCopy(isCopy, copiedFrom); + rightHalfCard.setCopy(isCopy, copiedFrom); + } + + private void setSideZones(Zone mainZone, Game game) { + switch (mainZone) { + case BATTLEFIELD: + case STACK: + throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main"); + default: + game.setZone(leftHalfCard.getId(), mainZone); + game.setZone(rightHalfCard.getId(), mainZone); + break; + } + checkGoodZones(game, this); + } + + @Override + public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { + if (super.moveToZone(toZone, source, game, flag, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + setSideZones(currentZone, game); + return true; + } + return false; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + setSideZones(zone, game); + } + + @Override + public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List appliedEffects) { + if (super.moveToExile(exileId, name, source, game, appliedEffects)) { + Zone currentZone = game.getState().getZone(getId()); + setSideZones(currentZone, game); + return true; + } + return false; + } + + /** + * Runtime check for good zones and other MDF data + */ + public static void checkGoodZones(Game game, DoubleFacedCard card) { + Card leftPart = card.getLeftHalfCard(); + Card rightPart = card.getRightHalfCard(); + + Zone zoneMain = game.getState().getZone(card.getId()); + Zone zoneLeft = game.getState().getZone(leftPart.getId()); + Zone zoneRight = game.getState().getZone(rightPart.getId()); + + // runtime check: + // * in battlefield and stack - card + one of the sides (another side in outside zone) + // * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack) + // + // 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack, + // it has only the characteristics of its front face. + // + // 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield, + // it has only the characteristics of the face that’s up. + Zone needZoneLeft; + Zone needZoneRight; + switch (zoneMain) { + case BATTLEFIELD: + case STACK: + if (zoneMain == zoneLeft) { + needZoneLeft = zoneMain; + needZoneRight = Zone.OUTSIDE; + } else if (zoneMain == zoneRight) { + needZoneLeft = Zone.OUTSIDE; + needZoneRight = zoneMain; + } else { + // impossible + needZoneLeft = zoneMain; + needZoneRight = Zone.OUTSIDE; + } + break; + default: + needZoneLeft = zoneMain; + needZoneRight = zoneMain; + break; + } + + if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) { + throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card + + "\r\n" + String.format("* main zone: %s", zoneMain) + + "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft) + + "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight)); + } + } + + @Override + public boolean removeFromZone(Game game, Zone fromZone, Ability source) { + // zone contains only one main card + return super.removeFromZone(game, fromZone, source); + } + + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + if (isCopy()) { // same as meld cards + super.updateZoneChangeCounter(game, event); + return; + } + super.updateZoneChangeCounter(game, event); + game.getState().updateZoneChangeCounter(leftHalfCard.getId()); + game.getState().updateZoneChangeCounter(rightHalfCard.getId()); + } + + @Override + public Counters getCounters(Game game) { + return getCounters(game.getState()); + } + + @Override + public Counters getCounters(GameState state) { + return state.getCardState(leftHalfCard.getId()).getCounters(); + } + + @Override + public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List appliedEffects, boolean isEffect, int maxCounters) { + return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters); + } + + @Override + public void removeCounters(String counterName, int amount, Ability source, Game game) { + leftHalfCard.removeCounters(counterName, amount, source, game); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (this.leftHalfCard.getSpellAbility() != null) { + this.leftHalfCard.getSpellAbility().setControllerId(controllerId); + } + if (this.rightHalfCard.getSpellAbility() != null) { + this.rightHalfCard.getSpellAbility().setControllerId(controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + + @Override + public List getSuperType(Game game) { + // CardImpl's constructor can call some code on init, so you must check left/right before + // it's a bad workaround + return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype; + } + + @Override + public List getCardType(Game game) { + // CardImpl's constructor can call some code on init, so you must check left/right before + // it's a bad workaround + return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType; + } + + @Override + public SubTypes getSubtype() { + // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. + // CardImpl's constructor can call some code on init, so you must check left/right before + return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype; + } + + @Override + public SubTypes getSubtype(Game game) { + // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. + // CardImpl's constructor can call some code on init, so you must check left/right before + return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype; + } + + @Override + public boolean hasSubtype(SubType subtype, Game game) { + return leftHalfCard.hasSubtype(subtype, game); + } + + @Override + public Abilities getAbilities() { + return getInnerAbilities(true, true); + } + + @Override + public Abilities getInitAbilities() { + // must init only parent related abilities, spell card must be init separately + return getInnerAbilities(false, false); + } + + public Abilities getSharedAbilities(Game game) { + // no shared abilities for mdf cards (e.g. must be left or right only) + return new AbilitiesImpl<>(); + } + + @Override + public Abilities getAbilities(Game game) { + return getInnerAbilities(game, true, true); + } + + private boolean isIgnoreDefaultAbility(Ability ability) { + // ignore default play/spell ability from main card (only halves are actual) + // default abilities added on card creation from card type and can't be skipped + + // skip cast spell + if (ability instanceof SpellAbility) { + SpellAbilityType type = ((SpellAbility) ability).getSpellAbilityType(); + return type == SpellAbilityType.MODAL || type == SpellAbilityType.TRANSFORMED; + } + + // skip play land + return ability instanceof PlayLandAbility; + } + + private boolean isIgnoreTransformSpellAbility(Ability ability) { + return ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.TRANSFORMED_RIGHT; + } + + private Abilities getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) { + Abilities allAbilites = new AbilitiesImpl<>(); + + for (Ability ability : super.getAbilities(game)) { + if (isIgnoreDefaultAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + + if (showLeftSide) { + allAbilites.addAll(leftHalfCard.getAbilities(game)); + } + if (showRightSide) { + for (Ability ability: rightHalfCard.getAbilities(game)) { + if (isIgnoreTransformSpellAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + } + + return allAbilites; + } + + private Abilities getInnerAbilities(boolean showLeftSide, boolean showRightSide) { + Abilities allAbilites = new AbilitiesImpl<>(); + + for (Ability ability : super.getAbilities()) { + if (isIgnoreDefaultAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + + if (showLeftSide) { + allAbilites.addAll(leftHalfCard.getAbilities()); + } + + if (showRightSide) { + for (Ability ability: rightHalfCard.getAbilities()) { + if (isIgnoreTransformSpellAbility(ability)) { + continue; + } + allAbilites.add(ability); + } + } + + return allAbilites; + } + + @Override + public List getRules() { + // rules must show only main side (another side visible by toggle/transform button in GUI) + // card hints from both sides + return CardUtil.getCardRulesWithAdditionalInfo( + this, + this.getInnerAbilities(true, false), + this.getInnerAbilities(true, true) + ); + } + + @Override + public List getRules(Game game) { + // rules must show only main side (another side visible by toggle/transform button in GUI) + // card hints from both sides + return CardUtil.getCardRulesWithAdditionalInfo( + game, + this, + this.getInnerAbilities(game, true, false), + this.getInnerAbilities(game, true, true) + ); + } + + @Override + public boolean hasAbility(Ability ability, Game game) { + return super.hasAbility(ability, game); + } + + @Override + public ObjectColor getColor() { + return leftHalfCard.getColor(); + } + + @Override + public ObjectColor getColor(Game game) { + return leftHalfCard.getColor(game); + } + + @Override + public ObjectColor getFrameColor(Game game) { + return leftHalfCard.getFrameColor(game); + } + + @Override + public void setOwnerId(UUID ownerId) { + super.setOwnerId(ownerId); + abilities.setControllerId(ownerId); + leftHalfCard.getAbilities().setControllerId(ownerId); + leftHalfCard.setOwnerId(ownerId); + rightHalfCard.getAbilities().setControllerId(ownerId); + rightHalfCard.setOwnerId(ownerId); + } + + @Override + public ManaCosts getManaCost() { + return leftHalfCard.getManaCost(); + } + + @Override + public int getManaValue() { + // Rules: + // The converted mana cost of a modal double-faced card is based on the characteristics of the + // face that’s being considered. On the stack and battlefield, consider whichever face is up. + // In all other zones, consider only the front face. This is different than how the converted + // mana cost of a transforming double-faced card is determined. + + // on stack or battlefield it must be half card with own cost + return leftHalfCard.getManaValue(); + } + + @Override + public MageInt getPower() { + return leftHalfCard.getPower(); + } + + @Override + public MageInt getToughness() { + return leftHalfCard.getToughness(); + } +} diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java b/Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java similarity index 67% rename from Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java rename to Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java index 2521b78aee8..c6bd6a390c3 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalfImpl.java +++ b/Mage/src/main/java/mage/cards/DoubleFacedCardHalf.java @@ -1,25 +1,25 @@ package mage.cards; -import mage.MageInt; import mage.abilities.Ability; import mage.constants.*; import mage.game.Game; +import mage.game.events.ZoneChangeEvent; import java.util.Arrays; import java.util.List; import java.util.UUID; /** - * @author JayDi85 + * @author JayDi85 - originally from ModalDoubleFaceCardHalf */ -public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubleFacedCardHalf { +public abstract class DoubleFacedCardHalf extends CardImpl implements SubCard { - ModalDoubleFacedCard parentCard; + protected DoubleFacedCard parentCard; - public ModalDoubleFacedCardHalfImpl( + public DoubleFacedCardHalf( UUID ownerId, CardSetInfo setInfo, SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, - String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + String costs, DoubleFacedCard parentCard, SpellAbilityType spellAbilityType ) { super(ownerId, setInfo, cardTypes, costs, spellAbilityType); this.supertype.addAll(Arrays.asList(cardSuperTypes)); @@ -27,7 +27,7 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl this.parentCard = parentCard; } - protected ModalDoubleFacedCardHalfImpl(final ModalDoubleFacedCardHalfImpl card) { + protected DoubleFacedCardHalf(final DoubleFacedCardHalf card) { super(card); this.parentCard = card.parentCard; } @@ -49,6 +49,11 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl return parentCard.getCardNumber(); } + @Override + public boolean isTransformable() { + return getOtherSide().isPermanent(); + } + @Override public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { return parentCard.moveToZone(toZone, source, game, flag, appliedEffects); @@ -65,25 +70,23 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl } @Override - public ModalDoubleFacedCard getMainCard() { + public Card getMainCard() { return parentCard; } + @Override + public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { + parentCard.updateZoneChangeCounter(game, event); + } + @Override public void setZone(Zone zone, Game game) { - // see ModalDoubleFacedCard.checkGoodZones for details + // see DoubleFacedCard.checkGoodZones for details game.setZone(parentCard.getId(), zone); game.setZone(this.getId(), zone); // find another side to sync - ModalDoubleFacedCardHalf otherSide; - if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) { - otherSide = parentCard.getLeftHalfCard(); - } else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) { - otherSide = parentCard.getRightHalfCard(); - } else { - throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); - } + Card otherSide = getOtherSide(); switch (zone) { case STACK: @@ -96,33 +99,39 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl break; } - ModalDoubleFacedCard.checkGoodZones(game, parentCard); + DoubleFacedCard.checkGoodZones(game, parentCard); + } + + public Card getOtherSide() { + Card otherSide; + if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) { + otherSide = parentCard.getLeftHalfCard(); + } else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) { + otherSide = parentCard.getRightHalfCard(); + } else { + throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); + } + return otherSide; + } + + public boolean isBackSide() { + if (parentCard.getLeftHalfCard().getId().equals(this.getId())) { + return false; + } else if (parentCard.getRightHalfCard().getId().equals(this.getId())) { + return true; + } else { + throw new IllegalStateException("Wrong code usage: MDF halves must use different ids"); + } } @Override - public ModalDoubleFacedCardHalfImpl copy() { - return new ModalDoubleFacedCardHalfImpl(this); - } - - @Override - public void setParentCard(ModalDoubleFacedCard card) { + public void setParentCard(DoubleFacedCard card) { this.parentCard = card; } @Override - public ModalDoubleFacedCard getParentCard() { - return this.parentCard; - } - - @Override - public void setPT(int power, int toughness) { - this.setPT(new MageInt(power), new MageInt(toughness)); - } - - @Override - public void setPT(MageInt power, MageInt toughness) { - this.power = power; - this.toughness = toughness; + public DoubleFacedCard getParentCard() { + return parentCard; } @Override diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java index eccfab302f2..cce1911e1bb 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java @@ -1,30 +1,15 @@ package mage.cards; -import mage.MageInt; -import mage.MageObject; -import mage.ObjectColor; import mage.abilities.*; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; import mage.constants.*; -import mage.counters.Counter; -import mage.counters.Counters; import mage.game.Game; -import mage.game.GameState; -import mage.game.events.ZoneChangeEvent; -import mage.util.CardUtil; -import mage.util.SubTypes; -import java.util.List; import java.util.UUID; /** * @author JayDi85 */ -public abstract class ModalDoubleFacedCard 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 +public abstract class ModalDoubleFacedCard extends DoubleFacedCard { public ModalDoubleFacedCard( UUID ownerId, CardSetInfo setInfo, @@ -48,184 +33,21 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH ) { super(ownerId, setInfo, typesLeft, costsLeft + costsRight, SpellAbilityType.MODAL); // main card name must be same as left side - leftHalfCard = new ModalDoubleFacedCardHalfImpl( + leftHalfCard = new ModalDoubleFacedCardHalf( this.getOwnerId(), setInfo.copy(), superTypesLeft, typesLeft, subTypesLeft, costsLeft, this, SpellAbilityType.MODAL_LEFT ); - rightHalfCard = new ModalDoubleFacedCardHalfImpl( + rightHalfCard = new ModalDoubleFacedCardHalf( this.getOwnerId(), new CardSetInfo(secondSideName, setInfo), superTypesRight, typesRight, subTypesRight, costsRight, this, SpellAbilityType.MODAL_RIGHT ); + this.secondSideCard = rightHalfCard; } - public ModalDoubleFacedCard(ModalDoubleFacedCard card) { + public ModalDoubleFacedCard(final ModalDoubleFacedCard card) { super(card); - // make sure all parts created and parent ref added - this.leftHalfCard = card.getLeftHalfCard().copy(); - ((ModalDoubleFacedCardHalf) leftHalfCard).setParentCard(this); - this.rightHalfCard = card.rightHalfCard.copy(); - ((ModalDoubleFacedCardHalf) rightHalfCard).setParentCard(this); - } - - public ModalDoubleFacedCardHalf getLeftHalfCard() { - return (ModalDoubleFacedCardHalf) leftHalfCard; - } - - public ModalDoubleFacedCardHalf getRightHalfCard() { - return (ModalDoubleFacedCardHalf) rightHalfCard; - } - - public void setParts(ModalDoubleFacedCardHalf leftHalfCard, ModalDoubleFacedCardHalf rightHalfCard) { - // for card copy only - set new parts - this.leftHalfCard = leftHalfCard; - leftHalfCard.setParentCard(this); - this.rightHalfCard = rightHalfCard; - rightHalfCard.setParentCard(this); - } - - @Override - public void assignNewId() { - super.assignNewId(); - leftHalfCard.assignNewId(); - rightHalfCard.assignNewId(); - } - - @Override - public void setCopy(boolean isCopy, MageObject copiedFrom) { - super.setCopy(isCopy, copiedFrom); - leftHalfCard.setCopy(isCopy, copiedFrom); // TODO: must check copiedFrom and assign sides? (??? related to #8476 ???) - rightHalfCard.setCopy(isCopy, copiedFrom); - } - - private void setSideZones(Zone mainZone, Game game) { - switch (mainZone) { - case BATTLEFIELD: - case STACK: - throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main"); - default: - // must keep both sides in same zone cause xmage need access to cost reduction, spell - // and other abilities before put it to stack (in playable calcs) - game.setZone(leftHalfCard.getId(), mainZone); - game.setZone(rightHalfCard.getId(), mainZone); - break; - } - checkGoodZones(game, this); - } - - @Override - public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List appliedEffects) { - if (super.moveToZone(toZone, source, game, flag, appliedEffects)) { - Zone currentZone = game.getState().getZone(getId()); - setSideZones(currentZone, game); - return true; - } - return false; - } - - @Override - public void setZone(Zone zone, Game game) { - super.setZone(zone, game); - setSideZones(zone, game); - } - - @Override - public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List appliedEffects) { - if (super.moveToExile(exileId, name, source, game, appliedEffects)) { - Zone currentZone = game.getState().getZone(getId()); - setSideZones(currentZone, game); - return true; - } - return false; - } - - /** - * Runtime check for good zones and other MDF data - */ - public static void checkGoodZones(Game game, ModalDoubleFacedCard card) { - Card leftPart = card.getLeftHalfCard(); - Card rightPart = card.getRightHalfCard(); - - Zone zoneMain = game.getState().getZone(card.getId()); - Zone zoneLeft = game.getState().getZone(leftPart.getId()); - Zone zoneRight = game.getState().getZone(rightPart.getId()); - - // runtime check: - // * in battlefield and stack - card + one of the sides (another side in outside zone) - // * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack) - // - // 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack, - // it has only the characteristics of its front face. - // - // 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield, - // it has only the characteristics of the face that’s up. - Zone needZoneLeft; - Zone needZoneRight; - switch (zoneMain) { - case BATTLEFIELD: - case STACK: - if (zoneMain == zoneLeft) { - needZoneLeft = zoneMain; - needZoneRight = Zone.OUTSIDE; - } else if (zoneMain == zoneRight) { - needZoneLeft = Zone.OUTSIDE; - needZoneRight = zoneMain; - } else { - // impossible - needZoneLeft = zoneMain; - needZoneRight = Zone.OUTSIDE; - } - break; - default: - needZoneLeft = zoneMain; - needZoneRight = zoneMain; - break; - } - - if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) { - throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card - + "\r\n" + String.format("* main zone: %s", zoneMain) - + "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft) - + "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight)); - } - } - - @Override - public boolean removeFromZone(Game game, Zone fromZone, Ability source) { - // zone contains only one main card - return super.removeFromZone(game, fromZone, source); - } - - @Override - public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { - if (isCopy()) { // same as meld cards - super.updateZoneChangeCounter(game, event); - return; - } - super.updateZoneChangeCounter(game, event); - leftHalfCard.updateZoneChangeCounter(game, event); - rightHalfCard.updateZoneChangeCounter(game, event); - } - - @Override - public Counters getCounters(Game game) { - return getCounters(game.getState()); - } - - @Override - public Counters getCounters(GameState state) { - return state.getCardState(leftHalfCard.getId()).getCounters(); - } - - @Override - public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List appliedEffects, boolean isEffect, int maxCounters) { - return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters); - } - - @Override - public void removeCounters(String counterName, int amount, Ability source, Game game) { - leftHalfCard.removeCounters(counterName, amount, source, game); } @Override @@ -236,201 +58,22 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH case MODAL_RIGHT: return this.rightHalfCard.cast(game, fromZone, ability, controllerId); default: - if (this.leftHalfCard.getSpellAbility() != null) { - this.leftHalfCard.getSpellAbility().setControllerId(controllerId); - } - if (this.rightHalfCard.getSpellAbility() != null) { - this.rightHalfCard.getSpellAbility().setControllerId(controllerId); - } return super.cast(game, fromZone, ability, controllerId); } } @Override - public List getSuperType(Game game) { - // CardImpl's constructor can call some code on init, so you must check left/right before - // it's a bad workaround - return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype; + public boolean isTransformable() { + return this.getLeftHalfCard().isPermanent() && this.getRightHalfCard().isPermanent(); } @Override - public List getCardType(Game game) { - // CardImpl's constructor can call some code on init, so you must check left/right before - // it's a bad workaround - return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType; + public ModalDoubleFacedCardHalf getLeftHalfCard() { + return (ModalDoubleFacedCardHalf) leftHalfCard; } @Override - public SubTypes getSubtype() { - // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. - // CardImpl's constructor can call some code on init, so you must check left/right before - return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype; - } - - @Override - public SubTypes getSubtype(Game game) { - // rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face. - // CardImpl's constructor can call some code on init, so you must check left/right before - return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype; - } - - @Override - public boolean hasSubtype(SubType subtype, Game game) { - return leftHalfCard.hasSubtype(subtype, game); - } - - @Override - public Abilities getAbilities() { - return getInnerAbilities(true, true); - } - - @Override - public Abilities getInitAbilities() { - // must init only parent related abilities, spell card must be init separately - return getInnerAbilities(false, false); - } - - public Abilities getSharedAbilities(Game game) { - // no shared abilities for mdf cards (e.g. must be left or right only) - return new AbilitiesImpl<>(); - } - - @Override - public Abilities getAbilities(Game game) { - return getInnerAbilities(game, true, true); - } - - private boolean isIgnoreDefaultAbility(Ability ability) { - // ignore default play/spell ability from main card (only halfes are actual) - // default abilities added on card creation from card type and can't be skipped - - // skip cast spell - if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.MODAL) { - return true; - } - - // skip play land - return ability instanceof PlayLandAbility; - } - - private Abilities getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) { - Abilities allAbilites = new AbilitiesImpl<>(); - - for (Ability ability : super.getAbilities(game)) { - if (isIgnoreDefaultAbility(ability)) { - continue; - } - allAbilites.add(ability); - } - - if (showLeftSide) { - allAbilites.addAll(leftHalfCard.getAbilities(game)); - } - if (showRightSide) { - allAbilites.addAll(rightHalfCard.getAbilities(game)); - } - - return allAbilites; - } - - private Abilities getInnerAbilities(boolean showLeftSide, boolean showRightSide) { - Abilities allAbilites = new AbilitiesImpl<>(); - - for (Ability ability : super.getAbilities()) { - if (isIgnoreDefaultAbility(ability)) { - continue; - } - allAbilites.add(ability); - } - - if (showLeftSide) { - allAbilites.addAll(leftHalfCard.getAbilities()); - } - - if (showRightSide) { - allAbilites.addAll(rightHalfCard.getAbilities()); - } - - return allAbilites; - } - - @Override - public List getRules() { - // rules must show only main side (another side visible by toggle/transform button in GUI) - // card hints from both sides - return CardUtil.getCardRulesWithAdditionalInfo( - this, - this.getInnerAbilities(true, false), - this.getInnerAbilities(true, true) - ); - } - - @Override - public List getRules(Game game) { - // rules must show only main side (another side visible by toggle/transform button in GUI) - // card hints from both sides - return CardUtil.getCardRulesWithAdditionalInfo( - game, - this, - this.getInnerAbilities(game, true, false), - this.getInnerAbilities(game, true, true) - ); - } - - @Override - public boolean hasAbility(Ability ability, Game game) { - return super.hasAbility(ability, game); - } - - @Override - public ObjectColor getColor() { - return leftHalfCard.getColor(); - } - - @Override - public ObjectColor getColor(Game game) { - return leftHalfCard.getColor(game); - } - - @Override - public ObjectColor getFrameColor(Game game) { - return leftHalfCard.getFrameColor(game); - } - - @Override - public void setOwnerId(UUID ownerId) { - super.setOwnerId(ownerId); - abilities.setControllerId(ownerId); - leftHalfCard.getAbilities().setControllerId(ownerId); - leftHalfCard.setOwnerId(ownerId); - rightHalfCard.getAbilities().setControllerId(ownerId); - rightHalfCard.setOwnerId(ownerId); - } - - @Override - public ManaCosts getManaCost() { - return leftHalfCard.getManaCost(); - } - - @Override - public int getManaValue() { - // Rules: - // The converted mana cost of a modal double-faced card is based on the characteristics of the - // face that’s being considered. On the stack and battlefield, consider whichever face is up. - // In all other zones, consider only the front face. This is different than how the converted - // mana cost of a transforming double-faced card is determined. - - // on stack or battlefield it must be half card with own cost - return leftHalfCard.getManaValue(); - } - - @Override - public MageInt getPower() { - return leftHalfCard.getPower(); - } - - @Override - public MageInt getToughness() { - return leftHalfCard.getToughness(); + public ModalDoubleFacedCardHalf getRightHalfCard() { + return (ModalDoubleFacedCardHalf) rightHalfCard; } } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java index 78cba6bd606..0626b54807b 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCardHalf.java @@ -1,16 +1,34 @@ package mage.cards; -import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.SuperType; -/** - * @author JayDi85 - */ -public interface ModalDoubleFacedCardHalf extends SubCard { +import java.util.UUID; + +public class ModalDoubleFacedCardHalf extends DoubleFacedCardHalf { + + public ModalDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, + String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + ) { + super(ownerId, setInfo, cardSuperTypes, cardTypes, cardSubTypes, costs, parentCard, spellAbilityType); + } + + protected ModalDoubleFacedCardHalf(final ModalDoubleFacedCardHalf card) { + super(card); + this.parentCard = card.parentCard; + } @Override - ModalDoubleFacedCardHalf copy(); + public ModalDoubleFacedCardHalf copy() { + return new ModalDoubleFacedCardHalf(this); + } - void setPT(int power, int toughness); - - void setPT(MageInt power, MageInt toughness); + @Override + public ModalDoubleFacedCard getParentCard() { + return (ModalDoubleFacedCard) parentCard; + } } diff --git a/Mage/src/main/java/mage/cards/RoomCard.java b/Mage/src/main/java/mage/cards/RoomCard.java new file mode 100644 index 00000000000..0380ff93064 --- /dev/null +++ b/Mage/src/main/java/mage/cards/RoomCard.java @@ -0,0 +1,172 @@ +package mage.cards; + +import mage.ObjectColor; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.RoomAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; + +import java.util.UUID; + +/** + * @author oscscull + */ +public abstract class RoomCard extends SplitCard { + private SpellAbilityType lastCastHalf = null; + + protected RoomCard(UUID ownerId, CardSetInfo setInfo, String costsLeft, String costsRight) { + super(ownerId, setInfo, costsLeft, costsRight, SpellAbilityType.SPLIT, new CardType[]{CardType.ENCHANTMENT}); + + String[] names = setInfo.getName().split(" // "); + + leftHalfCard = new RoomCardHalfImpl( + new CardSetInfo(names[0], setInfo), costsLeft, this, SpellAbilityType.SPLIT_LEFT + ); + rightHalfCard = new RoomCardHalfImpl( + new CardSetInfo(names[1], setInfo), costsRight, this, SpellAbilityType.SPLIT_RIGHT + ); + + // Add the one-shot effect to unlock a door on cast -> ETB + Ability entersAbility = new EntersBattlefieldAbility(new RoomEnterUnlockEffect()); + entersAbility.setRuleVisible(false); + this.addAbility(entersAbility); + + this.addAbility(new RoomAbility()); + } + + protected RoomCard(RoomCard card) { + super(card); + this.lastCastHalf = card.lastCastHalf; + } + + public SpellAbilityType getLastCastHalf() { + return lastCastHalf; + } + + public void setLastCastHalf(SpellAbilityType lastCastHalf) { + this.lastCastHalf = lastCastHalf; + } + + @Override + public Abilities getAbilities() { + return this.abilities; + } + + @Override + public Abilities getAbilities(Game game) { + return this.abilities; + } + + @Override + public void setZone(Zone zone, Game game) { + super.setZone(zone, game); + + if (zone == Zone.BATTLEFIELD) { + game.setZone(getLeftHalfCard().getId(), Zone.OUTSIDE); + game.setZone(getRightHalfCard().getId(), Zone.OUTSIDE); + return; + } + + game.setZone(getLeftHalfCard().getId(), zone); + game.setZone(getRightHalfCard().getId(), zone); + } + + public static void setRoomCharacteristics(Permanent permanent, Game game) { + if (!(permanent.getMainCard() instanceof RoomCard)) { + return; + } + setRoomCharacteristics(permanent, (RoomCard) permanent.getMainCard(), game, permanent.isLeftDoorUnlocked(), permanent.isRightDoorUnlocked()); + } + + // Static method for setting room characteristics on permanents + public static void setRoomCharacteristics(Permanent permanent, RoomCard roomCard, Game game, boolean isLeftUnlocked, boolean isRightUnlocked) { + permanent.setName(roomCard.name); + + permanent.setManaCost(roomCard.getManaCost()); + + // Set color indicator based on unlocked halves + ObjectColor newColor = new ObjectColor(); + if (isLeftUnlocked && roomCard.getLeftHalfCard() != null) { + newColor.addColor(roomCard.getLeftHalfCard().getColor()); + } + if (isRightUnlocked && roomCard.getRightHalfCard() != null) { + newColor.addColor(roomCard.getRightHalfCard().getColor()); + } + permanent.getColor().setColor(roomCard.getColor()); + + // Get abilities from each half + Abilities leftAbilities = roomCard.getLeftHalfCard().getAbilities(); + for (Ability ability : leftAbilities) { + permanent.addAbility(ability, roomCard.getLeftHalfCard().getId(), game, true); + } + + Abilities rightAbilities = roomCard.getRightHalfCard().getAbilities(); + for (Ability ability : rightAbilities) { + permanent.addAbility(ability, roomCard.getRightHalfCard().getId(), game, true); + } + } +} + +class RoomEnterUnlockEffect extends OneShotEffect { + public RoomEnterUnlockEffect() { + super(Outcome.Neutral); + staticText = ""; + } + + private RoomEnterUnlockEffect(final RoomEnterUnlockEffect effect) { + super(effect); + } + + @Override + public RoomEnterUnlockEffect copy() { + return new RoomEnterUnlockEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + + if (permanent == null) { + return false; + } + + if (permanent.wasRoomUnlockedOnCast()) { + return false; + } + + permanent.unlockRoomOnCast(game); + RoomCard roomCard = null; + // Get the parent card to access the lastCastHalf variable + if (permanent instanceof PermanentToken) { + Card mainCard = permanent.getMainCard(); + if (mainCard instanceof RoomCard) { + roomCard = (RoomCard) mainCard; + } + } else { + Card card = game.getCard(permanent.getId()); + if (card instanceof RoomCard) { + roomCard = (RoomCard) card; + } + } + if (roomCard == null) { + return true; + } + + SpellAbilityType lastCastHalf = roomCard.getLastCastHalf(); + + if (lastCastHalf == SpellAbilityType.SPLIT_LEFT || lastCastHalf == SpellAbilityType.SPLIT_RIGHT) { + roomCard.setLastCastHalf(null); + return permanent.unlockDoor(game, source, lastCastHalf == SpellAbilityType.SPLIT_LEFT); + } + + return true; + } +} diff --git a/Mage/src/main/java/mage/cards/RoomCardHalf.java b/Mage/src/main/java/mage/cards/RoomCardHalf.java new file mode 100644 index 00000000000..f6b1229b78b --- /dev/null +++ b/Mage/src/main/java/mage/cards/RoomCardHalf.java @@ -0,0 +1,9 @@ +package mage.cards; + +/** + * @author oscscull + */ +public interface RoomCardHalf extends SplitCardHalf { + @Override + RoomCardHalf copy(); +} diff --git a/Mage/src/main/java/mage/cards/RoomCardHalfImpl.java b/Mage/src/main/java/mage/cards/RoomCardHalfImpl.java new file mode 100644 index 00000000000..eee08e22d78 --- /dev/null +++ b/Mage/src/main/java/mage/cards/RoomCardHalfImpl.java @@ -0,0 +1,67 @@ +package mage.cards; + +import mage.abilities.SpellAbility; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author oscscull + */ +public class RoomCardHalfImpl extends SplitCardHalfImpl implements RoomCardHalf { + + public RoomCardHalfImpl(CardSetInfo setInfo, String costs, RoomCard splitCardParent, SpellAbilityType spellAbilityType) { + super(splitCardParent.ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, costs, splitCardParent, spellAbilityType); + this.addSubType(SubType.ROOM); + } + + protected RoomCardHalfImpl(final RoomCardHalfImpl card) { + super(card); + } + + @Override + public RoomCardHalfImpl copy() { + return new RoomCardHalfImpl(this); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + SpellAbilityType abilityType = ability.getSpellAbilityType(); + RoomCard parentCard = (RoomCard) this.getParentCard(); + + if (parentCard != null) { + if (abilityType == SpellAbilityType.SPLIT_LEFT) { + parentCard.setLastCastHalf(SpellAbilityType.SPLIT_LEFT); + } else if (abilityType == SpellAbilityType.SPLIT_RIGHT) { + parentCard.setLastCastHalf(SpellAbilityType.SPLIT_RIGHT); + } else { + parentCard.setLastCastHalf(null); + } + } + + return super.cast(game, fromZone, ability, controllerId); + } + + /** + * A room half is used for the spell half on the stack, similar to a normal split card. + * On the stack, it has only one name, mana cost, etc. + * However, in the hand and on the battlefield, it is the full card, which is the parent of the half. + * This code helps to ensure that the parent, and not the halves, are the only part of the card active on the battlefield. + * This is important for example when that half has a triggered ability etc that otherwise might trigger twice (once for the parent, once for the half) + * - in the case that the half was an object on the battlefield. In all other cases, they should all move together. + */ + @Override + public void setZone(Zone zone, Game game) { + if (zone == Zone.BATTLEFIELD) { + game.setZone(splitCardParent.getId(), zone); + game.setZone(splitCardParent.getLeftHalfCard().getId(), Zone.OUTSIDE); + game.setZone(splitCardParent.getRightHalfCard().getId(), Zone.OUTSIDE); + return; + } + super.setZone(zone, game); + } +} diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index 7595febd85b..740fcd00867 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -36,6 +36,15 @@ public abstract class SplitCard extends CardImpl implements CardWithHalves { rightHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), typesRight, costsRight, this, SpellAbilityType.SPLIT_RIGHT); } + // Params reordered as we need the same arguments as the parent constructor, with slightly different behaviour. + // Currently only used for rooms, because they are the only current split card with a shared type line. + protected SplitCard(UUID ownerId, CardSetInfo setInfo, String costsLeft, String costsRight, SpellAbilityType spellAbilityType, CardType[] singleTypeLine) { + super(ownerId, setInfo, singleTypeLine, costsLeft + costsRight, spellAbilityType); + String[] names = setInfo.getName().split(" // "); + leftHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[0], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), singleTypeLine, costsLeft, this, SpellAbilityType.SPLIT_LEFT); + rightHalfCard = new SplitCardHalfImpl(this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), singleTypeLine, costsRight, this, SpellAbilityType.SPLIT_RIGHT); + } + protected SplitCard(SplitCard card) { super(card); // make sure all parts created and parent ref added diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java new file mode 100644 index 00000000000..aa56e519844 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCard.java @@ -0,0 +1,66 @@ +package mage.cards; + +import mage.abilities.SpellAbility; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +public abstract class TransformingDoubleFacedCard extends DoubleFacedCard { + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + this( + ownerId, setInfo, + new SuperType[]{}, typesLeft, subTypesLeft, costsLeft, + secondSideName, + new SuperType[]{}, typesRight, subTypesRight, colorRight + ); + } + + public TransformingDoubleFacedCard( + UUID ownerId, CardSetInfo setInfo, + SuperType[] superTypesLeft, CardType[] typesLeft, SubType[] subTypesLeft, String costsLeft, + String secondSideName, + SuperType[] superTypesRight, CardType[] typesRight, SubType[] subTypesRight, String colorRight + ) { + super(ownerId, setInfo, typesLeft, costsLeft, SpellAbilityType.TRANSFORMED); + // main card name must be same as left side + leftHalfCard = new TransformingDoubleFacedCardHalf( + this.getOwnerId(), setInfo.copy(), + superTypesLeft, typesLeft, subTypesLeft, costsLeft, + this, SpellAbilityType.TRANSFORMED_LEFT + ); + rightHalfCard = new TransformingDoubleFacedCardHalf( + this.getOwnerId(), new CardSetInfo(secondSideName, setInfo), + superTypesRight, typesRight, subTypesRight, colorRight, this + ); + this.secondSideCard = rightHalfCard; + } + + public TransformingDoubleFacedCard(final TransformingDoubleFacedCard card) { + super(card); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (ability.getSpellAbilityType() == SpellAbilityType.BASE) { + return this.leftHalfCard.cast(game, fromZone, ability, controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + @Override + public TransformingDoubleFacedCardHalf getLeftHalfCard() { + return (TransformingDoubleFacedCardHalf) leftHalfCard; + } + + @Override + public TransformingDoubleFacedCardHalf getRightHalfCard() { + return (TransformingDoubleFacedCardHalf) rightHalfCard; + } +} diff --git a/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java new file mode 100644 index 00000000000..f82a910d852 --- /dev/null +++ b/Mage/src/main/java/mage/cards/TransformingDoubleFacedCardHalf.java @@ -0,0 +1,49 @@ +package mage.cards; + +import mage.ObjectColor; +import mage.abilities.SpellAbility; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +public class TransformingDoubleFacedCardHalf extends DoubleFacedCardHalf { + + public TransformingDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes, + String costs, TransformingDoubleFacedCard parentCard, SpellAbilityType spellAbilityType + ) { + super(ownerId, setInfo, cardSuperTypes, cardTypes, cardSubTypes, costs, parentCard, spellAbilityType); + } + + protected TransformingDoubleFacedCardHalf(final TransformingDoubleFacedCardHalf card) { + super(card); + this.parentCard = card.parentCard; + } + + public TransformingDoubleFacedCardHalf( + UUID ownerId, CardSetInfo setInfo, + SuperType[] superTypesRight, CardType[] typesRight, SubType[] subTypesRight, String colorRight, TransformingDoubleFacedCard parentCard) { + super(ownerId, setInfo, superTypesRight, typesRight, subTypesRight, "", parentCard, SpellAbilityType.TRANSFORMED_RIGHT); + this.getColor().setColor(new ObjectColor(colorRight)); + } + + @Override + public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { + if (ability.getSpellAbilityCastMode() == SpellAbilityCastMode.DISTURB && !isBackSide()) { + return getOtherSide().cast(game, fromZone, ability, controllerId); + } + return super.cast(game, fromZone, ability, controllerId); + } + + @Override + public TransformingDoubleFacedCardHalf copy() { + return new TransformingDoubleFacedCardHalf(this); + } + + @Override + public TransformingDoubleFacedCard getParentCard() { + return (TransformingDoubleFacedCard) parentCard; + } +} diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index 6d768ef8b67..04e28b30a09 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.cards.CardImpl; -import mage.cards.ModalDoubleFacedCard; +import mage.cards.DoubleFacedCard; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.util.CardUtil; @@ -35,7 +35,7 @@ public class MockCard extends CardImpl implements MockableCard { protected List manaCostRightStr; protected List manaCostStr; protected String spellOptionName; // adventure/omen spell name - protected boolean isModalDoubleFacedCard; + protected boolean isDoubleFacedCard; protected int manaValue; public MockCard(CardInfo card) { @@ -67,7 +67,7 @@ public class MockCard extends CardImpl implements MockableCard { this.nightCard = card.isNightCard(); - if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) { + if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty() && !card.isDoubleFacedCard()) { this.secondSideCard = new MockCard(CardRepository.instance.findCardWithPreferredSetAndNumber(card.getSecondSideName(), card.getSetCode(), card.getCardNumber())); } @@ -75,11 +75,11 @@ public class MockCard extends CardImpl implements MockableCard { this.spellOptionName = card.getSpellOptionCardName(); } - if (card.isModalDoubleFacedCard()) { - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card.createCard(); + if (card.isDoubleFacedCard()) { + DoubleFacedCard mdfCard = (DoubleFacedCard) card.createCard(); CardInfo mdfSecondSide = new CardInfo(mdfCard.getRightHalfCard()); this.secondSideCard = new MockCard(mdfSecondSide); - this.isModalDoubleFacedCard = true; + this.isDoubleFacedCard = true; } this.startingLoyalty = CardUtil.convertLoyaltyOrDefense(card.getStartingLoyalty()); @@ -102,7 +102,7 @@ public class MockCard extends CardImpl implements MockableCard { this.manaCostRightStr = new ArrayList<>(card.manaCostRightStr); this.manaCostStr = new ArrayList<>(card.manaCostStr); this.spellOptionName = card.spellOptionName; - this.isModalDoubleFacedCard = card.isModalDoubleFacedCard; + this.isDoubleFacedCard = card.isDoubleFacedCard; this.manaValue = card.manaValue; } @@ -157,7 +157,7 @@ public class MockCard extends CardImpl implements MockableCard { if (spellOptionName != null) { return getName() + CARD_WITH_SPELL_OPTION_NAME_SEPARATOR + spellOptionName; - } else if (isModalDoubleFacedCard) { + } else if (isDoubleFacedCard) { return getName() + MODAL_DOUBLE_FACES_NAME_SEPARATOR + this.getSecondCardFace().getName(); } else { return getName(); @@ -181,6 +181,6 @@ public class MockCard extends CardImpl implements MockableCard { @Override public boolean isTransformable() { // must enable toggle mode in deck editor (switch between card sides); - return super.isTransformable() || this.isModalDoubleFacedCard || this.secondSideCard != null; + return super.isTransformable() || this.isDoubleFacedCard || this.secondSideCard != null; } } diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index e9b8a2aab24..ecf3225f6fc 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -110,9 +110,9 @@ public class CardInfo { @DatabaseField protected String spellOptionCardName; @DatabaseField - protected boolean modalDoubleFacedCard; + protected boolean doubleFacedCard; @DatabaseField - protected String modalDoubleFacedSecondSideName; + protected String doubleFacedSecondSideName; @DatabaseField protected String meldsToCardName; @DatabaseField @@ -162,9 +162,9 @@ public class CardInfo { this.spellOptionCardName = ((CardWithSpellOption) card).getSpellCard().getName(); } - if (card instanceof ModalDoubleFacedCard) { - this.modalDoubleFacedCard = true; - this.modalDoubleFacedSecondSideName = ((ModalDoubleFacedCard) card).getRightHalfCard().getName(); + if (card instanceof DoubleFacedCard) { + this.doubleFacedCard = true; + this.doubleFacedSecondSideName = ((DoubleFacedCard) card).getRightHalfCard().getName(); } if (card.getFrameStyle() != null) { @@ -483,12 +483,12 @@ public class CardInfo { return spellOptionCardName; } - public boolean isModalDoubleFacedCard() { - return modalDoubleFacedCard; + public boolean isDoubleFacedCard() { + return doubleFacedCard; } - public String getModalDoubleFacedSecondSideName() { - return modalDoubleFacedSecondSideName; + public String getDoubleFacedSecondSideName() { + return doubleFacedSecondSideName; } @Override diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 9f6e39d6a75..d3ebbcfbc35 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -126,7 +126,7 @@ public enum CardRepository { } private void addNewNames(CardInfo card, Set namesList) { - // require before call: qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName"...); + // require before call: qb.distinct().selectColumns("name", "doubleFacedSecondSideName"...); // normal names int result = card.getName().indexOf(" // "); @@ -141,8 +141,8 @@ public enum CardRepository { if (card.getSecondSideName() != null && !card.getSecondSideName().isEmpty()) { namesList.add(card.getSecondSideName()); } - if (card.getModalDoubleFacedSecondSideName() != null && !card.getModalDoubleFacedSecondSideName().isEmpty()) { - namesList.add(card.getModalDoubleFacedSecondSideName()); + if (card.getDoubleFacedSecondSideName() != null && !card.getDoubleFacedSecondSideName().isEmpty()) { + namesList.add(card.getDoubleFacedSecondSideName()); } if (card.getFlipCardName() != null && !card.getFlipCardName().isEmpty()) { namesList.add(card.getFlipCardName()); @@ -166,7 +166,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { addNewNames(card, names); @@ -185,7 +185,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().not().like("types", new SelectArg('%' + CardType.LAND.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -205,7 +205,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("supertypes", '%' + SuperType.BASIC.name() + '%'), @@ -229,7 +229,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().not().like("supertypes", new SelectArg('%' + SuperType.BASIC.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -249,7 +249,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().like("types", new SelectArg('%' + CardType.CREATURE.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -269,7 +269,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); qb.where().like("types", new SelectArg('%' + CardType.ARTIFACT.name() + '%')); List results = cardsDao.query(qb.prepare()); for (CardInfo card : results) { @@ -289,7 +289,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("types", '%' + CardType.CREATURE.name() + '%'), @@ -313,7 +313,7 @@ public enum CardRepository { } try { QueryBuilder qb = cardsDao.queryBuilder(); - qb.distinct().selectColumns("name", "modalDoubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); + qb.distinct().selectColumns("name", "doubleFacedSecondSideName", "secondSideName", "flipCardName", "spellOptionCardName"); Where where = qb.where(); where.and( where.not().like("types", '%' + CardType.ARTIFACT.name() + '%'), @@ -539,7 +539,7 @@ public enum CardRepository { .eq("flipCardName", new SelectArg(name)).or() .eq("secondSideName", new SelectArg(name)).or() .eq("spellOptionCardName", new SelectArg(name)).or() - .eq("modalDoubleFacedSecondSideName", new SelectArg(name)); + .eq("doubleFacedSecondSideName", new SelectArg(name)); results = cardsDao.query(queryBuilder.prepare()); } else { // Check that a full card was found and not a SplitCardHalf diff --git a/Mage/src/main/java/mage/cards/repository/TokenRepository.java b/Mage/src/main/java/mage/cards/repository/TokenRepository.java index 819e2b20335..b2ddaef9cf1 100644 --- a/Mage/src/main/java/mage/cards/repository/TokenRepository.java +++ b/Mage/src/main/java/mage/cards/repository/TokenRepository.java @@ -272,6 +272,8 @@ public enum TokenRepository { res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 12, "https://api.scryfall.com/cards/tpip/1/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 13, "https://api.scryfall.com/cards/teoc/1/en?format=image")); res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 14, "https://api.scryfall.com/cards/tspm/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 15, "https://api.scryfall.com/cards/ttla/1/en?format=image")); + res.add(createXmageToken(XMAGE_IMAGE_NAME_COPY, 16, "https://api.scryfall.com/cards/ttla/2/en?format=image")); // City's Blessing // https://scryfall.com/search?q=type%3Atoken+include%3Aextras+unique%3Aprints+City%27s+Blessing+&unique=cards&as=grid&order=name diff --git a/Mage/src/main/java/mage/constants/AffinityType.java b/Mage/src/main/java/mage/constants/AffinityType.java index de6fb741683..104ace0f9cb 100644 --- a/Mage/src/main/java/mage/constants/AffinityType.java +++ b/Mage/src/main/java/mage/constants/AffinityType.java @@ -42,6 +42,7 @@ public enum AffinityType { BIRDS(new FilterControlledPermanent(SubType.BIRD, "Birds")), CITIZENS(new FilterControlledPermanent(SubType.CITIZEN, "Citizens")), SLIVERS(new FilterControlledPermanent(SubType.SLIVER, "Slivers")), + ALLIES(new FilterControlledPermanent(SubType.ALLY, "Allies"), "Ally"), TOWNS(new FilterControlledPermanent(SubType.TOWN, "Towns")), GATES(new FilterControlledPermanent(SubType.GATE, "Gates"), GatesYouControlHint.instance), SNOW_LANDS(AffinityFilters.SNOW_LANDS), diff --git a/Mage/src/main/java/mage/constants/EmptyNames.java b/Mage/src/main/java/mage/constants/EmptyNames.java index 350607b8f46..c882aa632b7 100644 --- a/Mage/src/main/java/mage/constants/EmptyNames.java +++ b/Mage/src/main/java/mage/constants/EmptyNames.java @@ -9,7 +9,8 @@ public enum EmptyNames { // TODO: replace all getName().equals to haveSameNames and haveEmptyName FACE_DOWN_CREATURE("", "[face_down_creature]"), // "Face down creature" FACE_DOWN_TOKEN("", "[face_down_token]"), // "Face down token" - FACE_DOWN_CARD("", "[face_down_card]"); // "Face down card" + FACE_DOWN_CARD("", "[face_down_card]"), // "Face down card" + FULLY_LOCKED_ROOM("", "[fully_locked_room]"); // "Fully locked room" public static final String EMPTY_NAME_IN_LOGS = "face down object"; @@ -40,7 +41,8 @@ public enum EmptyNames { public static boolean isEmptyName(String objectName) { return objectName.equals(FACE_DOWN_CREATURE.getObjectName()) || objectName.equals(FACE_DOWN_TOKEN.getObjectName()) - || objectName.equals(FACE_DOWN_CARD.getObjectName()); + || objectName.equals(FACE_DOWN_CARD.getObjectName()) + || objectName.equals(FULLY_LOCKED_ROOM.getObjectName()); } public static String replaceTestCommandByObjectName(String searchCommand) { diff --git a/Mage/src/main/java/mage/constants/PartnerVariantType.java b/Mage/src/main/java/mage/constants/PartnerVariantType.java new file mode 100644 index 00000000000..1c1d960f983 --- /dev/null +++ b/Mage/src/main/java/mage/constants/PartnerVariantType.java @@ -0,0 +1,81 @@ +package mage.constants; + +import mage.abilities.StaticAbility; +import mage.cards.Card; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public enum PartnerVariantType { + FATHER_AND_SON("Father & son"), + SURVIVORS("Survivors"), + CHARACTER_SELECT("Character select"); + + private final String name; + + PartnerVariantType(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public PartnerVariantAbility makeAbility() { + return new PartnerVariantAbility(this); + } + + private static Set getTypes(Card card) { + return CardUtil + .castStream(card.getAbilities(), PartnerVariantAbility.class) + .map(PartnerVariantAbility::getType) + .collect(Collectors.toSet()); + } + + public static boolean checkCommanders(Card commander1, Card commander2) { + Set types1 = getTypes(commander1); + if (types1.isEmpty()) { + return false; + } + Set types2 = getTypes(commander2); + if (types2.isEmpty()) { + return false; + } + types1.retainAll(types2); + return !types1.isEmpty(); + } +} + +class PartnerVariantAbility extends StaticAbility { + + private final PartnerVariantType type; + + PartnerVariantAbility(PartnerVariantType type) { + super(Zone.BATTLEFIELD, null); + this.type = type; + } + + private PartnerVariantAbility(final PartnerVariantAbility ability) { + super(ability); + this.type = ability.type; + } + + @Override + public PartnerVariantAbility copy() { + return new PartnerVariantAbility(this); + } + + public PartnerVariantType getType() { + return type; + } + + @Override + public String getRule() { + return "Partner—" + type + " (You can have two commanders if both have this ability.)"; + } +} diff --git a/Mage/src/main/java/mage/constants/PutCards.java b/Mage/src/main/java/mage/constants/PutCards.java index e23963b6746..2d93243ff52 100644 --- a/Mage/src/main/java/mage/constants/PutCards.java +++ b/Mage/src/main/java/mage/constants/PutCards.java @@ -2,11 +2,13 @@ package mage.constants; import mage.abilities.Ability; import mage.abilities.keyword.TransformAbility; -import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Set; /** * @author awjackson @@ -17,6 +19,7 @@ public enum PutCards { 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"), + BATTLEFIELD_TAPPED_ATTACKING(Outcome.PutCardInPlay, Zone.BATTLEFIELD, "onto the battlefield tapped and attacking"), BATTLEFIELD_TRANSFORMED(Outcome.PutCardInPlay, Zone.BATTLEFIELD, "onto the battlefield transformed"), EXILED(Outcome.Exile, Zone.EXILED, "into exile"), // may need special case code to generate correct text TOP_OR_BOTTOM(Outcome.Benefit, Zone.LIBRARY, "on the top or bottom of your library"), @@ -75,9 +78,21 @@ public enum PutCards { return player.putCardsOnBottomOfLibrary(new CardsImpl(card), game, source, false); case BATTLEFIELD_TAPPED: return player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); + case BATTLEFIELD_TAPPED_ATTACKING: + if (player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null)) { + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent != null) { + game.getCombat().addAttackingCreature(permanent.getId(), game); + } + return true; + } + return false; case SHUFFLE: return player.shuffleCardsToLibrary(card, game, source); case BATTLEFIELD_TRANSFORMED: + if (card instanceof TransformingDoubleFacedCard) { + card = ((TransformingDoubleFacedCard) card).getRightHalfCard(); + } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId(), Boolean.TRUE); case BATTLEFIELD: case EXILED: @@ -101,6 +116,18 @@ public enum PutCards { return player.putCardsOnBottomOfLibrary(cards, game, source, false); case BATTLEFIELD_TAPPED: return player.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); + case BATTLEFIELD_TAPPED_ATTACKING: + Set cardSet = cards.getCards(game); + if (player.moveCards(cardSet, Zone.BATTLEFIELD, source, game, true, false, false, null)) { + for (Card card : cardSet) { + Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game); + if (permanent != null) { + game.getCombat().addAttackingCreature(permanent.getId(), game); + } + } + return true; + } + return false; case SHUFFLE: return player.shuffleCardsToLibrary(cards, game, source); case BATTLEFIELD_TRANSFORMED: diff --git a/Mage/src/main/java/mage/constants/SpellAbilityType.java b/Mage/src/main/java/mage/constants/SpellAbilityType.java index fac7a218aef..a0da5bcd762 100644 --- a/Mage/src/main/java/mage/constants/SpellAbilityType.java +++ b/Mage/src/main/java/mage/constants/SpellAbilityType.java @@ -11,6 +11,9 @@ public enum SpellAbilityType { SPLIT_FUSED("Split SpellAbility"), SPLIT_LEFT("LeftSplit SpellAbility"), SPLIT_RIGHT("RightSplit SpellAbility"), + TRANSFORMED("Transformed SpellAbility"), + TRANSFORMED_LEFT("TransformFront SpellAbility"), + TRANSFORMED_RIGHT("TransformBack SpellAbility"), MODAL("Modal SpellAbility"), // used for modal double faces cards MODAL_LEFT("LeftModal SpellAbility"), MODAL_RIGHT("RightModal SpellAbility"), diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 50f81cc87e8..1cfe065e997 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -45,6 +45,7 @@ public enum SubType { CASE("Case", SubTypeSet.EnchantmentType), CLASS("Class", SubTypeSet.EnchantmentType), CURSE("Curse", SubTypeSet.EnchantmentType), + PLAN("Plan", SubTypeSet.EnchantmentType), ROLE("Role", SubTypeSet.EnchantmentType), ROOM("Room", SubTypeSet.EnchantmentType), RUNE("Rune", SubTypeSet.EnchantmentType), @@ -64,6 +65,7 @@ public enum SubType { JUNK("Junk", SubTypeSet.ArtifactType), LANDER("Lander", SubTypeSet.ArtifactType), MAP("Map", SubTypeSet.ArtifactType), + MUTAGEN("Mutagen", SubTypeSet.ArtifactType), POWERSTONE("Powerstone", SubTypeSet.ArtifactType), SPACECRAFT("Spacecraft", SubTypeSet.ArtifactType), TREASURE("Treasure", SubTypeSet.ArtifactType), @@ -192,6 +194,7 @@ public enum SubType { FUNGUS("Fungus", SubTypeSet.CreatureType), // G GAMER("Gamer", SubTypeSet.CreatureType), + GAMMA("Gamma", SubTypeSet.CreatureType), GAMORREAN("Gamorrean", SubTypeSet.CreatureType, true), // Star Wars GAND("Gand", SubTypeSet.CreatureType, true), // Star Wars GARGOYLE("Gargoyle", SubTypeSet.CreatureType), @@ -332,6 +335,7 @@ public enum SubType { PINCHER("Pincher", SubTypeSet.CreatureType), PIRATE("Pirate", SubTypeSet.CreatureType), PLANT("Plant", SubTypeSet.CreatureType), + PLATYPUS("Platypus", SubTypeSet.CreatureType), PORCUPINE("Porcupine", SubTypeSet.CreatureType), POSSUM("Possum", SubTypeSet.CreatureType), PRAETOR("Praetor", SubTypeSet.CreatureType), @@ -380,6 +384,7 @@ public enum SubType { SIREN("Siren", SubTypeSet.CreatureType), SITH("Sith", SubTypeSet.CreatureType), SKELETON("Skeleton", SubTypeSet.CreatureType), + SKRULL("Skrull", SubTypeSet.CreatureType), SKUNK("Skunk", SubTypeSet.CreatureType), SLITH("Slith", SubTypeSet.CreatureType), SLIVER("Sliver", SubTypeSet.CreatureType), @@ -389,6 +394,7 @@ public enum SubType { SNAKE("Snake", SubTypeSet.CreatureType), SOLDIER("Soldier", SubTypeSet.CreatureType), SOLTARI("Soltari", SubTypeSet.CreatureType), + SORCERER("Sorcerer", SubTypeSet.CreatureType), SPAWN("Spawn", SubTypeSet.CreatureType), SPECTER("Specter", SubTypeSet.CreatureType), SPELLSHAPER("Spellshaper", SubTypeSet.CreatureType), @@ -431,6 +437,7 @@ public enum SubType { // U UGNAUGHT("Ugnaught", SubTypeSet.CreatureType, true), UNICORN("Unicorn", SubTypeSet.CreatureType), + UTROM("Utrom", SubTypeSet.CreatureType), // V VAMPIRE("Vampire", SubTypeSet.CreatureType), VARMINT("Varmint", SubTypeSet.CreatureType), diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index c774348bd19..b5b5a74d71a 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -46,6 +46,7 @@ public enum CounterType { COLLECTION("collection"), COMPONENT("component"), CONTESTED("contested"), + CONQUEROR("conqueror"), CORPSE("corpse"), CORRUPTION("corruption"), CREDIT("credit"), diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 748c56a2dec..a33b7706d82 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -8,6 +8,7 @@ import mage.filter.common.*; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.*; import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.filter.predicate.other.TriggeredAbilityPredicate; import mage.filter.predicate.permanent.*; /** @@ -601,6 +602,13 @@ public final class StaticFilters { FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE.setLockedFilter(true); } + public static final FilterPermanent FILTER_ANOTHER_PERMANENT = new FilterPermanent("another permanent"); + + static { + FILTER_ANOTHER_PERMANENT.add(AnotherPredicate.instance); + FILTER_ANOTHER_PERMANENT.setLockedFilter(true); + } + public static final FilterCreaturePermanent FILTER_ANOTHER_CREATURE = new FilterCreaturePermanent("another creature"); static { @@ -902,6 +910,13 @@ public final class StaticFilters { FILTER_CONTROLLED_SAMURAI_OR_WARRIOR.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_ANOTHER_CONTROLLED_SHRINE = new FilterControlledPermanent(SubType.SHRINE, "another Shrine you control"); + + static { + FILTER_ANOTHER_CONTROLLED_SHRINE.add(AnotherPredicate.instance); + FILTER_ANOTHER_CONTROLLED_SHRINE.setLockedFilter(true); + } + public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKER = new FilterPlaneswalkerPermanent(); static { @@ -964,6 +979,14 @@ public final class StaticFilters { FILTER_SPELL_OR_ABILITY_A.setLockedFilter(true); } + public static final FilterStackObject FILTER_CONTROLLED_TRIGGERED_ABILITY = new FilterStackObject("triggered ability you control"); + + static { + FILTER_CONTROLLED_TRIGGERED_ABILITY.add(TriggeredAbilityPredicate.instance); + FILTER_CONTROLLED_TRIGGERED_ABILITY.add(TargetController.YOU.getControllerPredicate()); + FILTER_CONTROLLED_TRIGGERED_ABILITY.setLockedFilter(true); + } + public static final FilterCreatureSpell FILTER_SPELL_A_CREATURE = new FilterCreatureSpell("a creature spell"); static { 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 4160a68397c..7e5766d184c 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,6 @@ package mage.filter.predicate.mageobject; import mage.MageObject; -import mage.cards.CardWithHalves; import mage.cards.SplitCard; import mage.constants.SpellAbilityType; import mage.filter.predicate.Predicate; @@ -42,6 +41,7 @@ public class NamePredicate implements Predicate { if (name == null) { return false; } + // 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. // This is NOT the same for double faced cards, where only the front side matches @@ -51,28 +51,54 @@ public class NamePredicate implements Predicate { // including the one that you countered, because those cards have only their front-face characteristics // (including name) in the graveyard, hand, and library. (2021-04-16) + String[] searchNames = extractNames(name); + if (input instanceof SplitCard) { - 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 splitCard = (SplitCard) input; + // Check against left half, right half, and full card name + return matchesAnyName(searchNames, new String[] { + splitCard.getLeftHalfCard().getName(), + splitCard.getRightHalfCard().getName(), + splitCard.getName() + }); + } else if (input instanceof Spell + && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { SplitCard card = (SplitCard) ((Spell) input).getCard(); - return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, card.getName(), this.ignoreMtgRuleForEmptyNames); + // Check against left half, right half, and full card name + return matchesAnyName(searchNames, new String[] { + card.getLeftHalfCard().getName(), + card.getRightHalfCard().getName(), + card.getName() + }); } else if (input instanceof Spell && ((Spell) input).isFaceDown(game)) { // face down spells don't have names, so it's not equal, see https://github.com/magefree/mage/issues/6569 return false; } else { - if (name.contains(" // ")) { - String leftName = name.substring(0, name.indexOf(" // ")); - String rightName = name.substring(name.indexOf(" // ") + 4); - return CardUtil.haveSameNames(leftName, input.getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(rightName, input.getName(), this.ignoreMtgRuleForEmptyNames); - } else { - return CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); + // For regular cards, extract names from input and compare + String[] inputNames = extractNames(input.getName()); + return matchesAnyName(searchNames, inputNames); + } + } + + private String[] extractNames(String nameString) { + if (nameString.contains(" // ")) { + String leftName = nameString.substring(0, nameString.indexOf(" // ")); + String rightName = nameString.substring(nameString.indexOf(" // ") + 4); + return new String[] { leftName, rightName }; + } else { + return new String[] { nameString }; + } + } + + private boolean matchesAnyName(String[] searchNames, String[] targetNames) { + for (String searchName : searchNames) { + for (String targetName : targetNames) { + if (CardUtil.haveSameNames(searchName, targetName, this.ignoreMtgRuleForEmptyNames)) { + return true; + } } } + return false; } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/other/TriggeredAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/TriggeredAbilityPredicate.java new file mode 100644 index 00000000000..3b1f80fd693 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/TriggeredAbilityPredicate.java @@ -0,0 +1,18 @@ +package mage.filter.predicate.other; + +import mage.abilities.Ability; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.stack.StackObject; + +/** + * @author TheElk801 + */ +public enum TriggeredAbilityPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return input instanceof Ability && ((Ability) input).isTriggeredAbility(); + } +} diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 82d0ad5ce63..ff45386549a 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -56,6 +56,7 @@ import mage.game.mulligan.Mulligan; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; +import mage.game.permanent.PermanentToken; import mage.game.stack.Spell; import mage.game.stack.SpellStack; import mage.game.stack.StackAbility; @@ -129,8 +130,6 @@ public abstract class GameImpl implements Game { // For checking "becomes the target" triggers accurately. Cleared on short living LKI reset protected Map>> targetedMap = new HashMap<>(); - // Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield - protected Map permanentsEntering = new HashMap<>(); // used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist) protected Map enterWithCounters = new HashMap<>(); @@ -214,7 +213,6 @@ public abstract class GameImpl implements Game { this.lkiShortLiving = CardUtil.deepCopyObject(game.lkiShortLiving); this.targetedMap = CardUtil.deepCopyObject(game.targetedMap); - this.permanentsEntering = CardUtil.deepCopyObject(game.permanentsEntering); this.enterWithCounters = CardUtil.deepCopyObject(game.enterWithCounters); this.state = game.state.copy(); @@ -341,13 +339,13 @@ public abstract class GameImpl implements Game { Card rightCard = ((SplitCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); addCardToState(rightCard); - } else if (card instanceof ModalDoubleFacedCard) { + } else if (card instanceof DoubleFacedCard) { // left - Card leftCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + Card leftCard = ((DoubleFacedCard) card).getLeftHalfCard(); leftCard.setOwnerId(ownerId); addCardToState(leftCard); // right - Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + Card rightCard = ((DoubleFacedCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); addCardToState(rightCard); } else if (card instanceof CardWithSpellOption) { @@ -764,12 +762,12 @@ public abstract class GameImpl implements Game { @Override public Permanent getPermanentEntering(UUID permanentId) { - return permanentsEntering.get(permanentId); + return state.getBattlefield().getPermanentsEntering().get(permanentId); } @Override public Map getPermanentsEntering() { - return permanentsEntering; + return state.getBattlefield().getPermanentsEntering(); } @Override @@ -2109,6 +2107,7 @@ public abstract class GameImpl implements Game { newBluePrint = copyFromPermanent.copy(); // reset to original characteristics + newBluePrint.resetLockedStatus(); // reset locked status so room characteristics are correct newBluePrint.reset(this); // workaround to find real copyable characteristics of transformed/facedown/etc permanents @@ -2118,7 +2117,9 @@ public abstract class GameImpl implements Game { BecomesFaceDownCreatureEffect.makeFaceDownObject(this, null, newBluePrint, faceDownType, null); } newBluePrint.assignNewId(); - if (copyFromPermanent.isTransformed()) { + // TODO: should be able to remove after tdfc rework + if (copyFromPermanent.isTransformed() && (copyFromPermanent instanceof PermanentToken || ((copyFromPermanent instanceof PermanentCard) && + !(((PermanentCard) copyFromPermanent).getCard() instanceof DoubleFacedCardHalf)))) { TransformAbility.transformPermanent(newBluePrint, this, source); } if (copyFromPermanent.isPrototyped()) { @@ -3818,7 +3819,7 @@ public abstract class GameImpl implements Game { loadCards(ownerId, hand); loadCards(ownerId, battlefield .stream() - .map(PutToBattlefieldInfo::getCard) + .map(PutToBattlefieldInfo::getMainCard) .collect(Collectors.toList()) ); loadCards(ownerId, graveyard); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index c9963203f9e..86b38e24117 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -670,9 +670,9 @@ public class GameState implements Serializable, Copyable { for (Player player : players.values()) { player.reset(); } + this.reset(); battlefield.reset(game); combat.reset(game); - this.reset(); effects.apply(game); combat.checkForRemoveFromCombat(game); } @@ -1627,19 +1627,19 @@ public class GameState implements Serializable, Copyable { copiedParts.add(rightCopied); // sync parts ((SplitCard) copiedCard).setParts(leftCopied, rightCopied); - } else if (copiedCard instanceof ModalDoubleFacedCard) { + } else if (copiedCard instanceof DoubleFacedCard) { // left - ModalDoubleFacedCardHalf leftOriginal = ((ModalDoubleFacedCard) copiedCard).getLeftHalfCard(); - ModalDoubleFacedCardHalf leftCopied = leftOriginal.copy(); + DoubleFacedCardHalf leftOriginal = ((DoubleFacedCard) copiedCard).getLeftHalfCard(); + DoubleFacedCardHalf leftCopied = (DoubleFacedCardHalf) leftOriginal.copy(); prepareCardForCopy(leftOriginal, leftCopied, newController); copiedParts.add(leftCopied); // right - ModalDoubleFacedCardHalf rightOriginal = ((ModalDoubleFacedCard) copiedCard).getRightHalfCard(); - ModalDoubleFacedCardHalf rightCopied = rightOriginal.copy(); + DoubleFacedCardHalf rightOriginal = ((DoubleFacedCard) copiedCard).getRightHalfCard(); + DoubleFacedCardHalf rightCopied = (DoubleFacedCardHalf) rightOriginal.copy(); prepareCardForCopy(rightOriginal, rightCopied, newController); copiedParts.add(rightCopied); // sync parts - ((ModalDoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied); + ((DoubleFacedCard) copiedCard).setParts(leftCopied, rightCopied); } else if (copiedCard instanceof CardWithSpellOption) { // right SpellOptionCard rightOriginal = ((CardWithSpellOption) copiedCard).getSpellCard(); diff --git a/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java b/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java index 404cde602e6..912157935a8 100644 --- a/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java +++ b/Mage/src/main/java/mage/game/PutToBattlefieldInfo.java @@ -21,6 +21,10 @@ public class PutToBattlefieldInfo { return card; } + public Card getMainCard() { + return card.getMainCard(); + } + public boolean isTapped() { return tapped; } diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index d6aa18cd37c..ad215f21baf 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -89,21 +89,31 @@ public final class ZonesHandler { ZoneChangeInfo info = itr.next(); if (info.event.getToZone().equals(Zone.BATTLEFIELD)) { Card card = game.getCard(info.event.getTargetId()); - if (card instanceof ModalDoubleFacedCard || card instanceof ModalDoubleFacedCardHalf) { + if (card instanceof DoubleFacedCard || card instanceof DoubleFacedCardHalf) { boolean forceToMainSide = false; + // TODO: move transform key or have some other identifier after tdfc rework + Boolean enterTransformed = (Boolean) game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()); + if (enterTransformed == null) { + enterTransformed = false; + } // if effect put half mdf card to battlefield then it must be the main side only (example: return targeted half card to battle) - if (card instanceof ModalDoubleFacedCardHalf && !source.getAbilityType().isPlayCardAbility()) { + if (card instanceof DoubleFacedCardHalf && !source.getAbilityType().isPlayCardAbility() && !enterTransformed) { forceToMainSide = true; } // if effect put mdf card to battlefield then it must be main side only - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { forceToMainSide = true; } if (forceToMainSide) { - info.event.setTargetId(((ModalDoubleFacedCard) card.getMainCard()).getLeftHalfCard().getId()); + info.event.setTargetId(((DoubleFacedCard) card.getMainCard()).getLeftHalfCard().getId()); + } + + // if left half is being moved, but entering transformed, change to transformed side + if (enterTransformed && card instanceof DoubleFacedCardHalf && !((DoubleFacedCardHalf) card).isBackSide()) { + info.event.setTargetId(((DoubleFacedCardHalf) card).getOtherSide().getId()); } } } @@ -154,10 +164,10 @@ public final class ZonesHandler { // meld/group cards must be independent (use can choose order) cardsToMove = ((MeldCard) targetCard).getHalves(); cardsToUpdate.get(toZone).addAll(cardsToMove); - } else if (targetCard instanceof ModalDoubleFacedCard - || targetCard instanceof ModalDoubleFacedCardHalf) { + } else if (targetCard instanceof DoubleFacedCard + || targetCard instanceof DoubleFacedCardHalf) { // mdf cards must be moved as single object, but each half must be updated separately - ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) targetCard.getMainCard(); + DoubleFacedCard mdfCard = (DoubleFacedCard) targetCard.getMainCard(); cardsToMove = new CardsImpl(mdfCard); cardsToUpdate.get(toZone).add(mdfCard); // example: cast left side @@ -191,6 +201,28 @@ public final class ZonesHandler { cardsToUpdate.get(toZone).add(mdfCard.getRightHalfCard()); break; } + } else if (targetCard instanceof RoomCard || targetCard instanceof RoomCardHalf) { + // Room cards must be moved as single object + RoomCard roomCard = (RoomCard) targetCard.getMainCard(); + cardsToMove = new CardsImpl(roomCard); + cardsToUpdate.get(toZone).add(roomCard); + switch (toZone) { + case STACK: + case BATTLEFIELD: + // We don't want room halves to ever be on the battlefield + cardsToUpdate.get(Zone.OUTSIDE).add(roomCard.getLeftHalfCard()); + cardsToUpdate.get(Zone.OUTSIDE).add(roomCard.getRightHalfCard()); + break; + default: + // move all parts + cardsToUpdate.get(toZone).add(roomCard.getLeftHalfCard()); + cardsToUpdate.get(toZone).add(roomCard.getRightHalfCard()); + // If we aren't casting onto the stack or etb'ing, we need to clear this state + // (countered, memory lapsed etc) + // This prevents the state persisting for a put into play effect later + roomCard.setLastCastHalf(null); + break; + } } else { cardsToMove = new CardsImpl(targetCard); cardsToUpdate.get(toZone).addAll(cardsToMove); @@ -269,7 +301,11 @@ public final class ZonesHandler { } // update zone in main - game.setZone(event.getTargetId(), event.getToZone()); + if (targetCard instanceof RoomCardHalf && (toZone == Zone.BATTLEFIELD)) { + game.setZone(event.getTargetId(), Zone.OUTSIDE); + } else { + game.setZone(event.getTargetId(), event.getToZone()); + } // update zone in other parts (meld cards, mdf half cards) cardsToUpdate.entrySet().forEach(entry -> { @@ -347,8 +383,9 @@ public final class ZonesHandler { * that isn't a transforming double-faced card onto the battlefield transformed or converted, that card stays in * its current zone. */ + // TODO: remove after tdfc rework boolean wantToTransform = Boolean.TRUE.equals(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId())); - if (wantToTransform) { + if (wantToTransform && !(card instanceof DoubleFacedCardHalf)) { isGoodToMove = card.isTransformable() && card.getSecondCardFace().isPermanent(game); } else { isGoodToMove = card.isPermanent(game); @@ -378,7 +415,10 @@ public final class ZonesHandler { Permanent permanent; if (card instanceof MeldCard) { permanent = new PermanentMeld(card, event.getPlayerId(), game); - } else if (card instanceof ModalDoubleFacedCard) { + } else if (card instanceof RoomCardHalf) { + // Only the main room card can etb + permanent = new PermanentCard(card.getMainCard(), event.getPlayerId(), game); + } else if (card instanceof DoubleFacedCard) { // main mdf card must be processed before that call (e.g. only halves can be moved to battlefield) throw new IllegalStateException("Unexpected trying of move mdf card to battlefield instead half"); } else if (card instanceof Permanent) { diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index 9940f345875..9e264afa759 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -679,29 +679,6 @@ public class CombatGroup implements Serializable, Copyable { possibleBlockers.put(attacker.getId(), goodBlockers); } - // effects: can't block alone - // too much blockers - if (blockersCount == 1) { - List toBeRemoved = new ArrayList<>(); - for (UUID blockerId : getBlockers()) { - Permanent blocker = game.getPermanent(blockerId); - if (blocker != null && blocker.getAbilities().containsKey(CantBlockAloneAbility.getInstance().getId())) { - blockWasLegal = false; - if (!game.isSimulation()) { - game.informPlayers(blocker.getLogName() + " can't block alone. Removing it from combat."); - } - toBeRemoved.add(blockerId); - } - } - - for (UUID blockerId : toBeRemoved) { - game.getCombat().removeBlocker(blockerId, game); - } - if (blockers.isEmpty()) { - this.blocked = false; - } - } - for (UUID uuid : attackers) { Permanent attacker = game.getPermanent(uuid); if (attacker != null && this.blocked) { diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 7ff69e6101d..24f01ee4f2c 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -52,6 +52,7 @@ public class Commander extends CommandObjectImpl { case MODAL: case MODAL_LEFT: case MODAL_RIGHT: + case TRANSFORMED_LEFT: case ADVENTURE_SPELL: // can be used from command zone if (canUseAbilityFromCommandZone(spellAbility)) { diff --git a/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java b/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java index cf3f474532d..af72e38b5bc 100644 --- a/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/InzervaMasterOfInsightsEmblem.java @@ -23,7 +23,7 @@ public final class InzervaMasterOfInsightsEmblem extends Emblem { )); // Whenever an opponent draws a card, this emblem deals 1 damage to them this.getAbilities().add(new DrawCardOpponentTriggeredAbility( - Zone.COMMAND, new DamageTargetEffect(1, true, "them") + Zone.COMMAND, new DamageTargetEffect(1) .setText("this emblem deals 1 damage to them"), false, true )); } diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index ed46fcc7717..47cc932a337 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -699,6 +699,19 @@ public class GameEvent implements Serializable { AIRBENDED, FIREBENDED, WATERBENDED, + /* A room permanent has a door unlocked. + targetId the room permanent + sourceId the unlock ability + playerId the room permanent's controller + flag true = left door unlocked false = right door unlocked + */ + DOOR_UNLOCKED, + /* A room permanent has a door unlocked. + targetId the room permanent + sourceId the unlock ability + playerId the room permanent's controller + */ + ROOM_FULLY_UNLOCKED, // custom events - must store some unique data to track CUSTOM_EVENT; diff --git a/Mage/src/main/java/mage/game/permanent/Battlefield.java b/Mage/src/main/java/mage/game/permanent/Battlefield.java index 7a57d75d044..094c03eecad 100644 --- a/Mage/src/main/java/mage/game/permanent/Battlefield.java +++ b/Mage/src/main/java/mage/game/permanent/Battlefield.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; public class Battlefield implements Serializable { private final Map field = new LinkedHashMap<>(); + private final Map permanentsEntering = new LinkedHashMap<>(); public Battlefield() { } @@ -26,6 +27,9 @@ public class Battlefield implements Serializable { for (Entry entry : battlefield.field.entrySet()) { field.put(entry.getKey(), entry.getValue().copy()); } + for (Entry entry : battlefield.permanentsEntering.entrySet()) { + permanentsEntering.put(entry.getKey(), entry.getValue().copy()); + } } public Battlefield copy() { @@ -36,10 +40,14 @@ public class Battlefield implements Serializable { for (Permanent perm : field.values()) { perm.reset(game); } + for (Permanent perm : permanentsEntering.values()) { + perm.reset(game); + } } public void clear() { field.clear(); + permanentsEntering.clear(); } /** @@ -156,6 +164,11 @@ public class Battlefield implements Serializable { return field.containsKey(key); } + public Map getPermanentsEntering() { + return permanentsEntering; + } + + public void beginningOfTurn(Game game) { for (Permanent perm : field.values()) { perm.beginningOfTurn(game); diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 3b88aff182b..97ef2ba3491 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -223,7 +223,10 @@ public interface Permanent extends Card, Controllable { boolean fight(Permanent fightTarget, Ability source, Game game); - boolean fight(Permanent fightTarget, Ability source, Game game, boolean batchTrigger); + /** + * Resolves a fight and returns the amount of excess damage dealt to fightTarget + */ + int fightWithExcess(Permanent fightTarget, Ability source, Game game, boolean batchTrigger); boolean entersBattlefield(Ability source, Game game, Zone fromZone, boolean fireEvent); @@ -474,6 +477,23 @@ public interface Permanent extends Card, Controllable { void setHarnessed(boolean value); + boolean wasRoomUnlockedOnCast(); + + /** + * used to reset the locked status of a room. Only used when copying a room + * or creating a token copy of a room permanent. Could most likely be removed + * after a designation class added. + */ + void resetLockedStatus(); + + boolean isLeftDoorUnlocked(); + + boolean isRightDoorUnlocked(); + + boolean unlockRoomOnCast(Game game); + + boolean unlockDoor(Game game, Ability source, boolean isLeftDoor); + @Override Permanent copy(); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index b7ef957b100..9139caea669 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -1,8 +1,10 @@ package mage.game.permanent; import mage.MageObject; +import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.Ability; +import mage.abilities.common.RoomAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.NightboundAbility; @@ -30,6 +32,8 @@ public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; protected int zoneChangeCounter; + protected ObjectColor originalColor; + protected ObjectColor originalFrameColor; public PermanentCard(Card card, UUID controllerId, Game game) { super(card.getId(), card.getOwnerId(), controllerId, card.getName()); // card id @@ -46,11 +50,12 @@ public class PermanentCard extends PermanentImpl { // if you use it in test code or for permanent's copy effects then call CardUtil.getDefaultCardSideForBattlefield for default side // it's a basic check and still allows to create permanent from instant or sorcery boolean goodForBattlefield = true; - if (card instanceof ModalDoubleFacedCard) { + if (card instanceof DoubleFacedCard) { goodForBattlefield = false; } else if (card instanceof SplitCard) { // fused spells allowed (it uses main card) - if (card.getSpellAbility() != null && !card.getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { + // room spells allowed (it uses main card) + if (card.getSpellAbility() != null && !card.getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED) && !(card instanceof RoomCard)) { goodForBattlefield = false; } } @@ -64,9 +69,24 @@ public class PermanentCard extends PermanentImpl { throw new IllegalArgumentException("Wrong code usage: can't create permanent card from split or mdf: " + card.getName()); } - this.card = card; + // if two permanent sides, set front and second side + if (card instanceof DoubleFacedCardHalf && card.isPermanent() && ((DoubleFacedCardHalf) card).getOtherSide().isPermanent()) { + if (((DoubleFacedCardHalf) card).isBackSide()) { + secondSideCard = card; + this.card = ((DoubleFacedCardHalf) card).getOtherSide().copy(); + this.transformed = true; + init(secondSideCard, game); + } else { + secondSideCard = ((DoubleFacedCardHalf) card).getOtherSide().copy(); + this.card = card; + init(card, game); + } + } else { + this.card = card; + init(card, game); + } + this.zoneChangeCounter = card.getZoneChangeCounter(game); // local value already set to the raised number - init(card, game); } private void init(Card card, Game game) { @@ -74,7 +94,7 @@ public class PermanentCard extends PermanentImpl { toughness = card.getToughness().copy(); startingLoyalty = card.getStartingLoyalty(); startingDefense = card.getStartingDefense(); - copyFromCard(card, game); + copyFromCard(card, game, false); // 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()); if (otherAbilities != null) { @@ -85,10 +105,11 @@ public class PermanentCard extends PermanentImpl { } // if transformed on ETB - if (card.isTransformable()) { - if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId()) != null + // TODO: remove after tdfc rework + if (card.isTransformable() && !(card instanceof DoubleFacedCardHalf)) { + if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null || NightboundAbility.checkCard(this, game)) { - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getId(), null); + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId(), null); TransformAbility.transformPermanent(this, game, null); } } @@ -99,19 +120,37 @@ public class PermanentCard extends PermanentImpl { this.card = permanent.card.copy(); this.maxLevelCounters = permanent.maxLevelCounters; this.zoneChangeCounter = permanent.zoneChangeCounter; + this.originalColor = permanent.originalColor.copy(); + this.originalFrameColor = permanent.originalFrameColor.copy(); } @Override public void reset(Game game) { // when the permanent is reset, copy all original values from the card // must copy card each reset so that the original values don't get modified - copyFromCard(card, game); + if (transformed && secondSideCard != null && getCard() instanceof DoubleFacedCardHalf) { + copyFromCard(secondSideCard, game, true); + } else { + copyFromCard(card, game, true); + } power.resetToBaseValue(); toughness.resetToBaseValue(); super.reset(game); } - protected void copyFromCard(final Card card, final Game game) { + @Override + protected void initOtherFace(Game game) { + if (!(secondSideCard instanceof DoubleFacedCardHalf)) { + return; + } + if (transformed) { + copyFromCard(secondSideCard, game, false); + } else { + copyFromCard(card, game, false); + } + } + + protected void copyFromCard(final Card card, final Game game, boolean isReset) { // TODO: must research - is it copy all fields or something miss this.name = card.getName(); this.abilities.clear(); @@ -121,6 +160,11 @@ public class PermanentCard extends PermanentImpl { this.abilities.add(ability.copy()); } } + } else if (card.getId() != this.getId()) { + // if different id, abilities need to be added to game state for continuous/triggers + for (Ability ability : card.getAbilities()) { + this.addAbility(ability, card.getId(), game, true); + } } else { // copy only own abilities; all dynamic added abilities must be added in the parent call this.abilities = card.getAbilities().copy(); @@ -130,13 +174,23 @@ public class PermanentCard extends PermanentImpl { this.abilities.setSourceId(objectId); this.cardType.clear(); this.cardType.addAll(card.getCardType()); - this.color = card.getColor(game).copy(); - this.frameColor = card.getFrameColor(game).copy(); + if (!isReset) { + // save color from game state on first creation + this.color = card.getColor(game).copy(); + this.frameColor = card.getFrameColor(game).copy(); + this.originalColor = card.getColor(game).copy(); + this.originalFrameColor = card.getFrameColor(game).copy(); + } else { + this.color = originalColor.copy(); + this.frameColor = originalFrameColor.copy(); + } this.frameStyle = card.getFrameStyle(); this.manaCost = card.getManaCost().copy(); if (card instanceof PermanentCard) { this.maxLevelCounters = ((PermanentCard) card).maxLevelCounters; } + this.power = card.getPower().copy(); + this.toughness = card.getToughness().copy(); this.subtype.copyFrom(card.getSubtype()); this.supertype.clear(); this.supertype.addAll(card.getSuperType()); @@ -148,7 +202,7 @@ public class PermanentCard extends PermanentImpl { this.setImageFileName(card.getImageFileName()); this.setImageNumber(card.getImageNumber()); - if (card.getSecondCardFace() != null) { + if (card.getSecondCardFace() != null && !(card instanceof DoubleFacedCardHalf)) { this.secondSideCardClazz = card.getSecondCardFace().getClass(); } if (card.getMeldsToCard() != null) { @@ -157,6 +211,22 @@ public class PermanentCard extends PermanentImpl { this.nightCard = card.isNightCard(); this.flipCard = card.isFlipCard(); this.flipCardName = card.getFlipCardName(); + // Rooms set characteristics at the end so nothing gets overwritten + if (card instanceof RoomCard) { + RoomCard.setRoomCharacteristics(this, game); + if (!isReset) { + RoomAbility roomAbility = null; + for (Ability ability : this.abilities) { + if (ability instanceof RoomAbility) { + roomAbility = (RoomAbility) ability; + break; + } + } + if (roomAbility != null) { + roomAbility.applyCharacteristics(game, this); + } + } + } } @Override diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index f800b17f368..1b096877cdc 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -17,6 +17,7 @@ import mage.abilities.hint.HintUtils; import mage.abilities.keyword.*; import mage.cards.Card; import mage.cards.CardImpl; +import mage.abilities.common.RoomAbility; import mage.constants.*; import mage.counters.Counter; import mage.counters.CounterType; @@ -102,6 +103,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected boolean deathtouched; protected boolean solved = false; + protected boolean roomWasUnlockedOnCast = false; + protected boolean leftHalfUnlocked = false; + protected boolean rightHalfUnlocked = false; protected Map> connectedCards = new HashMap<>(); protected Set dealtDamageByThisTurn; protected UUID attachedTo; @@ -191,6 +195,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.morphed = permanent.morphed; this.disguised = permanent.disguised; + this.leftHalfUnlocked = permanent.leftHalfUnlocked; + this.rightHalfUnlocked = permanent.rightHalfUnlocked; + this.roomWasUnlockedOnCast = permanent.roomWasUnlockedOnCast; this.manifested = permanent.manifested; this.cloaked = permanent.cloaked; this.createOrder = permanent.createOrder; @@ -700,12 +707,15 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { + CardUtil.getSourceLogName(game, source, this.getId())); this.setTransformed(!this.transformed); this.transformCount++; + initOtherFace(game); game.applyEffects(); // not process action - no firing of simultaneous events yet this.replaceEvent(EventType.TRANSFORMING, game); game.addSimultaneousEvent(GameEvent.getEvent(EventType.TRANSFORMED, this.getId(), this.getControllerId())); return true; } + protected abstract void initOtherFace(Game game); + @Override public int getTransformCount() { return transformCount; @@ -2018,16 +2028,17 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean fight(Permanent fightTarget, Ability source, Game game) { - return this.fight(fightTarget, source, game, true); + this.fightWithExcess(fightTarget, source, game, true); + return true; } @Override - public boolean fight(Permanent fightTarget, Ability source, Game game, boolean batchTrigger) { + public int fightWithExcess(Permanent fightTarget, Ability source, Game game, boolean batchTrigger) { // double fight events for each creature game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FIGHTED_PERMANENT, fightTarget.getId(), source, source.getControllerId())); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FIGHTED_PERMANENT, getId(), source, source.getControllerId())); damage(fightTarget.getPower().getValue(), fightTarget.getId(), source, game); - fightTarget.damage(getPower().getValue(), getId(), source, game); + int excess = fightTarget.damageWithExcess(getPower().getValue(), getId(), source, game); if (batchTrigger) { Set morSet = new HashSet<>(); @@ -2038,7 +2049,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BATCH_FIGHT, getId(), source, source.getControllerId(), data, 0)); } - return true; + return excess; } @Override @@ -2086,4 +2097,83 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return ZonesHandler.moveCard(zcInfo, game, source); } + + @Override + public boolean wasRoomUnlockedOnCast() { + return roomWasUnlockedOnCast; + } + + @Override + public void resetLockedStatus() { + leftHalfUnlocked = false; + rightHalfUnlocked = false; + } + + @Override + public boolean isLeftDoorUnlocked() { + return leftHalfUnlocked; + } + + @Override + public boolean isRightDoorUnlocked() { + return rightHalfUnlocked; + } + + @Override + public boolean unlockRoomOnCast(Game game) { + if (this.roomWasUnlockedOnCast) { + return false; + } + this.roomWasUnlockedOnCast = true; + return true; + } + + @Override + public boolean unlockDoor(Game game, Ability source, boolean isLeftDoor) { + // Check if already unlocked + boolean thisDoorUnlocked = isLeftDoor ? leftHalfUnlocked : rightHalfUnlocked; + if (thisDoorUnlocked) { + return false; + } + + // Log the unlock + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + String doorSide = isLeftDoor ? "left" : "right"; + game.informPlayers(controller.getLogName() + " unlocked the " + doorSide + " door of " + + getLogName() + CardUtil.getSourceLogName(game, source)); + } + + // Update unlock state + if (isLeftDoor) { + leftHalfUnlocked = true; + } else { + rightHalfUnlocked = true; + } + + // Update intrinsic stats/abilities from unlocking + // find the RoomCharacteristicsEffect applied by this permanent's ability + Abilities abilities = this.getAbilities(game); + for (Ability ability : abilities) { + if (ability instanceof RoomAbility) { + ((RoomAbility) ability).restoreUnlockedStats(game, this); + break; + } + } + + // Create door unlock event + GameEvent event = new GameEvent(GameEvent.EventType.DOOR_UNLOCKED, getId(), source, source.getControllerId()); + event.setFlag(isLeftDoor); + + // Check if room is now fully unlocked + boolean otherDoorUnlocked = isLeftDoor ? rightHalfUnlocked : leftHalfUnlocked; + if (otherDoorUnlocked) { + game.addSimultaneousEvent(event); + game.addSimultaneousEvent(new GameEvent(EventType.ROOM_FULLY_UNLOCKED, getId(), source, source.getControllerId())); + } else { + game.fireEvent(event); + } + + return true; + } } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index 36825c296a0..024be2a2275 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -5,8 +5,8 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.keyword.ChangelingAbility; -import mage.abilities.keyword.TransformAbility; import mage.cards.Card; +import mage.cards.RoomCard; import mage.constants.EmptyNames; import mage.game.Game; import mage.game.events.ZoneChangeEvent; @@ -30,13 +30,13 @@ public class PermanentToken extends PermanentImpl { this.token = token.copy(); this.token.getAbilities().newOriginalId(); // neccessary if token has ability like DevourAbility() this.token.getAbilities().setSourceId(objectId); - this.power = new MageInt(token.getPower().getModifiedBaseValue()); - this.toughness = new MageInt(token.getToughness().getModifiedBaseValue()); - this.copyFromToken(this.token, game, false); // needed to have at this time (e.g. for subtypes for entersTheBattlefield replacement effects) // if transformed on ETB if (this.token.isEntersTransformed()) { - TransformAbility.transformPermanent(this, game, null); + this.setTransformed(true); + this.copyFromToken(this.token.getBackFace(), game, false); + } else { + this.copyFromToken(this.token, game, false); // needed to have at this time (e.g. for subtypes for entersTheBattlefield replacement effects) } // token's ZCC must be synced with original token to keep abilities settings @@ -53,7 +53,11 @@ public class PermanentToken extends PermanentImpl { @Override public void reset(Game game) { - copyFromToken(token, game, true); + if (this.isTransformed()) { + copyFromToken(token.getBackFace(), game, true); + } else { + copyFromToken(token, game, true); + } super.reset(game); // Because the P/T objects have there own base value for reset we have to take it from there instead of from the basic token object this.power.resetToBaseValue(); @@ -110,8 +114,12 @@ public class PermanentToken extends PermanentImpl { if (this.abilities.containsClass(ChangelingAbility.class)) { this.subtype.setIsAllCreatureTypes(true); } - + this.power = new MageInt(token.getPower().getModifiedBaseValue()); + this.toughness = new MageInt(token.getToughness().getModifiedBaseValue()); CardUtil.copySetAndCardNumber(this, token); + if (token.getCopySourceCard() instanceof RoomCard) { + RoomCard.setRoomCharacteristics(this, game); + } } @Override @@ -138,7 +146,13 @@ public class PermanentToken extends PermanentImpl { @Override public Card getMainCard() { - // token don't have game card, so return itself + // Check if we have a copy source card (for tokens created from copied spells) + Card copySourceCard = token.getCopySourceCard(); + if (copySourceCard != null) { + return copySourceCard; + } + + // Fallback to current behavior return this; } @@ -155,4 +169,13 @@ public class PermanentToken extends PermanentImpl { public MageObject getOtherFace() { return this.transformed ? token : this.token.getBackFace(); } + + @Override + protected void initOtherFace(Game game) { + if (transformed) { + copyFromToken(token.getBackFace(), game, false); + } else { + copyFromToken(token, game, false); + } + } } diff --git a/Mage/src/main/java/mage/game/permanent/token/WallToken.java b/Mage/src/main/java/mage/game/permanent/token/BasaltGolemToken.java similarity index 71% rename from Mage/src/main/java/mage/game/permanent/token/WallToken.java rename to Mage/src/main/java/mage/game/permanent/token/BasaltGolemToken.java index 00ffad3b5bb..eeec6781c3f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WallToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BasaltGolemToken.java @@ -8,9 +8,9 @@ import mage.constants.SubType; /** * @author lagdotcom */ -public final class WallToken extends TokenImpl { +public final class BasaltGolemToken extends TokenImpl { - public WallToken() { + public BasaltGolemToken() { super("Wall Token", "0/2 colorless Wall artifact creature token with defender"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); @@ -20,11 +20,11 @@ public final class WallToken extends TokenImpl { addAbility(DefenderAbility.getInstance()); } - private WallToken(final WallToken token) { + private BasaltGolemToken(final BasaltGolemToken token) { super(token); } - public WallToken copy() { - return new WallToken(this); + public BasaltGolemToken copy() { + return new BasaltGolemToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java b/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java index b5e4f4fe03d..b4ccf693cfb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java @@ -1,8 +1,7 @@ package mage.game.permanent.token; import mage.MageInt; -import mage.abilities.keyword.CantAttackAloneAbility; -import mage.abilities.keyword.CantBlockAloneAbility; +import mage.abilities.keyword.CantAttackOrBlockAloneAbility; import mage.constants.CardType; import mage.constants.SubType; @@ -19,8 +18,7 @@ public final class BeastieToken extends TokenImpl { power = new MageInt(4); toughness = new MageInt(4); - this.addAbility(new CantAttackAloneAbility()); - this.addAbility(CantBlockAloneAbility.getInstance()); + this.addAbility(new CantAttackOrBlockAloneAbility()); } private BeastieToken(final BeastieToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/Demon66Token.java b/Mage/src/main/java/mage/game/permanent/token/Demon66Token.java new file mode 100644 index 00000000000..c292b5b538c --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Demon66Token.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class Demon66Token extends TokenImpl { + + public Demon66Token() { + super("Demon Token", "6/6 black Demon creature token with flying"); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.DEMON); + power = new MageInt(6); + toughness = new MageInt(6); + addAbility(FlyingAbility.getInstance()); + } + + private Demon66Token(final Demon66Token token) { + super(token); + } + + @Override + public Demon66Token copy() { + return new Demon66Token(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/DoombotToken.java b/Mage/src/main/java/mage/game/permanent/token/DoombotToken.java new file mode 100644 index 00000000000..eb2edf84eb9 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/DoombotToken.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 DoombotToken extends TokenImpl { + + public DoombotToken() { + super("Doombot", "3/3 colorless Robot Villain artifact creature token named Doombot"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.ROBOT); + subtype.add(SubType.VILLAIN); + power = new MageInt(3); + toughness = new MageInt(3); + } + + private DoombotToken(final DoombotToken token) { + super(token); + } + + public DoombotToken copy() { + return new DoombotToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonFirebendingToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonFirebendingToken.java new file mode 100644 index 00000000000..c6fd93d29cb --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/DragonFirebendingToken.java @@ -0,0 +1,32 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.FirebendingAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class DragonFirebendingToken extends TokenImpl { + + public DragonFirebendingToken() { + super("Dragon Token", "4/4 red Dragon creature token with flying and firebending 4"); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add(SubType.DRAGON); + power = new MageInt(4); + toughness = new MageInt(4); + addAbility(FlyingAbility.getInstance()); + addAbility(new FirebendingAbility(4)); + } + + private DragonFirebendingToken(final DragonFirebendingToken token) { + super(token); + } + + public DragonFirebendingToken copy() { + return new DragonFirebendingToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java index d5be3d0f3ee..dc2ba7b3d96 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieBlueBlackToken.java @@ -6,17 +6,16 @@ import mage.constants.CardType; import mage.constants.SubType; /** - * @author spjspj + * @author TheElk801 */ public final class FaerieBlueBlackToken extends TokenImpl { public FaerieBlueBlackToken() { - super("Faerie Rogue Token", "1/1 blue and black Faerie Rogue creature token with flying"); + super("Faerie Token", "1/1 blue and black Faerie creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setBlack(true); subtype.add(SubType.FAERIE); - subtype.add(SubType.ROGUE); power = new MageInt(1); toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage/src/main/java/mage/game/permanent/token/GalactusToken.java b/Mage/src/main/java/mage/game/permanent/token/GalactusToken.java new file mode 100644 index 00000000000..b1c5ad47449 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/GalactusToken.java @@ -0,0 +1,44 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.target.common.TargetLandPermanent; + +/** + * @author TheElk801 + */ +public final class GalactusToken extends TokenImpl { + + public GalactusToken() { + super("Galactus", "Galactus, a legendary 16/16 black Elder Alien creature token with flying, trample, and \"Whenever Galactus attacks, destroy target land.\""); + supertype.add(SuperType.LEGENDARY); + cardType.add(CardType.CREATURE); + subtype.add(SubType.ELDER); + subtype.add(SubType.ALIEN); + + color.setBlack(true); + power = new MageInt(16); + toughness = new MageInt(16); + + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(TrampleAbility.getInstance()); + Ability ability = new AttacksTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetLandPermanent()); + this.addAbility(ability); + } + + private GalactusToken(final GalactusToken token) { + super(token); + } + + public GalactusToken copy() { + return new GalactusToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/MutagenToken.java b/Mage/src/main/java/mage/game/permanent/token/MutagenToken.java new file mode 100644 index 00000000000..6171901f91a --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MutagenToken.java @@ -0,0 +1,40 @@ +package mage.game.permanent.token; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author TheElk801 + */ +public final class MutagenToken extends TokenImpl { + + public MutagenToken() { + super("Mutagen Token", "Mutagen token"); + cardType.add(CardType.ARTIFACT); + subtype.add(SubType.MUTAGEN); + + Ability ability = new ActivateAsSorceryActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new GenericManaCost(1) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost().setText("sacrifice this token")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private MutagenToken(final MutagenToken token) { + super(token); + } + + public MutagenToken copy() { + return new MutagenToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/TheVoidToken.java b/Mage/src/main/java/mage/game/permanent/token/TheVoidToken.java new file mode 100644 index 00000000000..6ff4514f894 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/TheVoidToken.java @@ -0,0 +1,39 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.AttacksEachCombatStaticAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +/** + * @author TheElk801 + */ +public final class TheVoidToken extends TokenImpl { + + public TheVoidToken() { + super("The Void", "The Void, a legendary 5/5 black Horror Villain creature token with flying, indestructible, and \"The Void attacks each combat if able.\""); + supertype.add(SuperType.LEGENDARY); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HORROR); + subtype.add(SubType.VILLAIN); + + color.setBlack(true); + power = new MageInt(5); + toughness = new MageInt(5); + + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(IndestructibleAbility.getInstance()); + this.addAbility(new AttacksEachCombatStaticAbility()); + } + + private TheVoidToken(final TheVoidToken token) { + super(token); + } + + public TheVoidToken copy() { + return new TheVoidToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/ToyToken.java b/Mage/src/main/java/mage/game/permanent/token/ToyToken.java new file mode 100644 index 00000000000..53c32ed2ebd --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/ToyToken.java @@ -0,0 +1,30 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class ToyToken extends TokenImpl { + + public ToyToken() { + super("Toy Token", "1/1 white Toy artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.TOY); + color.setWhite(true); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private ToyToken(final ToyToken token) { + super(token); + } + + @Override + public ToyToken copy() { + return new ToyToken(this); + } +} 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 f5b0d1c0bf9..de93c7ee3de 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java @@ -1,13 +1,10 @@ package mage.game.permanent.token; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsCombatDamageTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; public final class VrondissRageOfAncientsToken extends TokenImpl { @@ -21,7 +18,7 @@ public final class VrondissRageOfAncientsToken extends TokenImpl { power = new MageInt(5); toughness = new MageInt(4); - this.addAbility(new VrondissRageOfAncientsTokenTriggeredAbility()); + this.addAbility(new DealsCombatDamageTriggeredAbility(new SacrificeSourceEffect(), false)); } private VrondissRageOfAncientsToken(final VrondissRageOfAncientsToken token) { @@ -32,35 +29,3 @@ public final class VrondissRageOfAncientsToken extends TokenImpl { return new VrondissRageOfAncientsToken(this); } } - -class VrondissRageOfAncientsTokenTriggeredAbility extends TriggeredAbilityImpl { - - public VrondissRageOfAncientsTokenTriggeredAbility() { - super(Zone.BATTLEFIELD, new SacrificeSourceEffect(), false); - } - - protected VrondissRageOfAncientsTokenTriggeredAbility(final VrondissRageOfAncientsTokenTriggeredAbility ability) { - super(ability); - } - - @Override - public VrondissRageOfAncientsTokenTriggeredAbility copy() { - return new VrondissRageOfAncientsTokenTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER - || event.getType() == GameEvent.EventType.DAMAGED_PERMANENT; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.getSourceId()); - } - - @Override - public String getRule() { - return "When this creature deals damage, sacrifice it."; - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/WallColorlessReachToken.java b/Mage/src/main/java/mage/game/permanent/token/WallColorlessReachToken.java new file mode 100644 index 00000000000..befd19724e9 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WallColorlessReachToken.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.ReachAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class WallColorlessReachToken extends TokenImpl { + + public WallColorlessReachToken() { + super("Wall Token", "0/3 colorless Wall creature token with defender and reach"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WALL); + power = new MageInt(0); + toughness = new MageInt(3); + addAbility(DefenderAbility.getInstance()); + addAbility(ReachAbility.getInstance()); + } + + private WallColorlessReachToken(final WallColorlessReachToken token) { + super(token); + } + + public WallColorlessReachToken copy() { + return new WallColorlessReachToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/WallColorlessToken.java b/Mage/src/main/java/mage/game/permanent/token/WallColorlessToken.java new file mode 100644 index 00000000000..969299ebcae --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WallColorlessToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.DefenderAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class WallColorlessToken extends TokenImpl { + + public WallColorlessToken() { + super("Wall Token", "0/4 colorless Wall creature token with defender"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WALL); + power = new MageInt(0); + toughness = new MageInt(4); + addAbility(DefenderAbility.getInstance()); + } + + private WallColorlessToken(final WallColorlessToken token) { + super(token); + } + + public WallColorlessToken copy() { + return new WallColorlessToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index e9de92a4a63..e9b54a60375 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -2,6 +2,7 @@ package mage.game.stack; import mage.*; import mage.abilities.*; +import mage.abilities.common.SpellTransformedAbility; import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; @@ -102,6 +103,11 @@ public class Spell extends StackObjectImpl implements Card { this.ability = ability; this.ability.setControllerId(controllerId); + // 712.8c TDFC spell "Its mana value is calculated using the mana cost of its front face" + if(ability instanceof SpellTransformedAbility && manaCost.isEmpty()) { + this.manaCost = card.getMainCard().getManaCost().copy(); + this.ability.setSourceId(affectedCard.getId()); // Maybe wrong? Permanent has incorrect id otherwise + } if (ability.getSpellAbilityCastMode().isFaceDown()) { // TODO: need research: // - why it use game param for color and subtype (possible bug?) @@ -1187,6 +1193,16 @@ public class Spell extends StackObjectImpl implements Card { throw new UnsupportedOperationException("Not supported."); } + @Override + public void setPT(int power, int toughness) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void setPT(MageInt power, MageInt toughness) { + throw new UnsupportedOperationException("Not supported."); + } + @Override public boolean cantBeAttachedBy(MageObject attachment, Ability source, Game game, boolean silentMode) { throw new UnsupportedOperationException("Not supported."); @@ -1223,8 +1239,8 @@ public class Spell extends StackObjectImpl implements Card { } @Override - public void looseAllAbilities(Game game) { - throw new UnsupportedOperationException("Spells should not loose all abilities. Check if this operation is correct."); + public void loseAllAbilities(Game game) { + throw new UnsupportedOperationException("Spells should not lose all abilities. Check if this operation is correct."); } @Override diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index 1311c7408fa..ae06cef17e3 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -42,6 +42,7 @@ public class ManaPool implements Serializable { // empty mana pool effects private final Set doNotEmptyManaTypes = new HashSet<>(); // keep some colors private boolean manaBecomesBlack = false; // replace all pool by black + private boolean manaBecomesRed = false; // replace all pool by red private boolean manaBecomesColorless = false; // replace all pool by colorless private static final class ConditionalManaInfo { @@ -76,6 +77,7 @@ public class ManaPool implements Serializable { } this.doNotEmptyManaTypes.addAll(pool.doNotEmptyManaTypes); this.manaBecomesBlack = pool.manaBecomesBlack; + this.manaBecomesRed = pool.manaBecomesRed; this.manaBecomesColorless = pool.manaBecomesColorless; } @@ -236,6 +238,7 @@ public class ManaPool implements Serializable { public void clearEmptyManaPoolRules() { doNotEmptyManaTypes.clear(); this.manaBecomesBlack = false; + this.manaBecomesRed = false; this.manaBecomesColorless = false; } @@ -247,6 +250,10 @@ public class ManaPool implements Serializable { this.manaBecomesBlack = manaBecomesBlack; } + public void setManaBecomesRed(boolean manaBecomesRed) { + this.manaBecomesRed = manaBecomesRed; + } + public void setManaBecomesColorless(boolean manaBecomesColorless) { this.manaBecomesColorless = manaBecomesColorless; } @@ -267,6 +274,9 @@ public class ManaPool implements Serializable { if (manaBecomesBlack) { continue; } + if (manaBecomesRed) { + continue; + } if (manaBecomesColorless) { continue; } @@ -315,12 +325,20 @@ public class ManaPool implements Serializable { return 0; } } + + // TODO: This should be reimplemented as replacement effects instead, so you can choose which applies. if (manaBecomesBlack) { int amount = toEmpty.get(manaType); toEmpty.clear(manaType); toEmpty.add(ManaType.BLACK, amount); return 0; } + if (manaBecomesRed) { + int amount = toEmpty.get(manaType); + toEmpty.clear(manaType); + toEmpty.add(ManaType.RED, amount); + return 0; + } if (manaBecomesColorless) { int amount = toEmpty.get(manaType); toEmpty.clear(manaType); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index ef0b43ea920..e2c6348cbaa 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -4106,7 +4106,11 @@ public abstract class PlayerImpl implements Player, Serializable { getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, mainCard.getRightHalfCard(), mainCard.getRightHalfCard().getAbilities(game), availableMana, output); getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); - } else if (object instanceof CardWithSpellOption) { + } else if (object instanceof TransformingDoubleFacedCard) { + TransformingDoubleFacedCard mainCard = (TransformingDoubleFacedCard) object; + getPlayableFromObjectSingle(game, fromZone, mainCard.getLeftHalfCard(), mainCard.getLeftHalfCard().getAbilities(game), availableMana, output); + getPlayableFromObjectSingle(game, fromZone, mainCard, mainCard.getSharedAbilities(game), availableMana, output); + } else if (object instanceof CardWithSpellOption) { // adventure must use different card characteristics for different spells (main or adventure) CardWithSpellOption cardWithSpellOption = (CardWithSpellOption) object; getPlayableFromObjectSingle(game, fromZone, cardWithSpellOption.getSpellCard(), cardWithSpellOption.getSpellCard().getAbilities(game), availableMana, output); @@ -4258,6 +4262,12 @@ public abstract class PlayerImpl implements Player, Serializable { boolean isPlaySpell = (ability instanceof SpellAbility); boolean isPlayLand = (ability instanceof PlayLandAbility); + // ignore backside of TDFC + // TODO: maybe better way to ignore + if (isPlaySpell && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.TRANSFORMED_RIGHT) { + continue; + } + // play land restrictions if (isPlayLand && game.getContinuousEffects().preventedByRuleModification( GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, ability.getSourceId(), @@ -4946,8 +4956,9 @@ public abstract class PlayerImpl implements Player, Serializable { // or "converted," it enters the battlefield with its back face up. If a player is instructed to put a card // that isn't a transforming double-faced card onto the battlefield transformed or converted, that card stays in // its current zone. + // TODO: can probably remove/change after tdfc rework, should only be sending transformed side Boolean enterTransformed = (Boolean) game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()); - if (enterTransformed != null && enterTransformed && !card.isTransformable()) { + if (enterTransformed != null && enterTransformed && !card.isTransformable() && !(card instanceof TransformingDoubleFacedCardHalf)) { continue; } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index e0a00773cc2..ffb46ca4c70 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -141,6 +141,7 @@ public abstract class TargetImpl implements Target { addTargetWord = false; } else if (targetName.endsWith("any target") || targetName.endsWith("any other target") + || targetName.endsWith("another target") || targetName.endsWith("targets")) { addTargetWord = false; } diff --git a/Mage/src/main/java/mage/target/TargetOptimization.java b/Mage/src/main/java/mage/target/TargetOptimization.java index 879b32e5f57..5e9ab5128ac 100644 --- a/Mage/src/main/java/mage/target/TargetOptimization.java +++ b/Mage/src/main/java/mage/target/TargetOptimization.java @@ -26,54 +26,19 @@ public class TargetOptimization { // for up to or any amount - limit max game sims to analyse // (it's useless to calc all possible combinations on too much targets) - static public int AI_MAX_POSSIBLE_TARGETS_TO_CHOOSE = 7; + static public int AI_MAX_POSSIBLE_TARGETS_TO_CHOOSE = 18; public static void optimizePossibleTargets(Ability source, Game game, Set possibleTargets, int maxPossibleTargetsToSimulate) { // remove duplicated/same creatures // example: distribute 3 damage between 10+ same tokens // example: target x1 from x10 forests - it's useless to recalc each forest - if (possibleTargets.size() < maxPossibleTargetsToSimulate) { + if (possibleTargets.size() <= maxPossibleTargetsToSimulate) { return; } // split targets by groups - Map targetGroups = new HashMap<>(); - possibleTargets.forEach(id -> { - String groupKey = ""; - - // player - Player player = game.getPlayer(id); - if (player != null) { - groupKey = getTargetGroupKeyAsPlayer(player); - } - - // game object - MageObject object = game.getObject(id); - if (object != null) { - groupKey = object.getName(); - if (object instanceof Permanent) { - groupKey += getTargetGroupKeyAsPermanent(game, (Permanent) object); - } else if (object instanceof Card) { - groupKey += getTargetGroupKeyAsCard(game, (Card) object); - } else { - groupKey += getTargetGroupKeyAsOther(game, object); - } - } - - // unknown - use all - if (groupKey.isEmpty()) { - groupKey = id.toString(); - } - - targetGroups.put(id, groupKey); - }); - - Map> groups = new HashMap<>(); - targetGroups.forEach((id, groupKey) -> { - groups.computeIfAbsent(groupKey, k -> new ArrayList<>()); - groups.get(groupKey).add(id); - }); + Map> targetGroups = createGroups(game, possibleTargets, maxPossibleTargetsToSimulate, false); // optimize logic: // - use one target from each target group all the time @@ -81,7 +46,7 @@ public class TargetOptimization { // use one target per group Set newPossibleTargets = new HashSet<>(); - groups.forEach((groupKey, groupTargets) -> { + targetGroups.forEach((groupKey, groupTargets) -> { UUID targetId = RandomUtil.randomFromCollection(groupTargets); if (targetId != null) { newPossibleTargets.add(targetId); @@ -91,13 +56,13 @@ public class TargetOptimization { // use random target until fill condition while (newPossibleTargets.size() < maxPossibleTargetsToSimulate) { - String groupKey = RandomUtil.randomFromCollection(groups.keySet()); + String groupKey = RandomUtil.randomFromCollection(targetGroups.keySet()); if (groupKey == null) { break; } - List groupTargets = groups.getOrDefault(groupKey, null); + List groupTargets = targetGroups.getOrDefault(groupKey, null); if (groupTargets == null || groupTargets.isEmpty()) { - groups.remove(groupKey); + targetGroups.remove(groupKey); continue; } UUID targetId = RandomUtil.randomFromCollection(groupTargets); @@ -112,6 +77,49 @@ public class TargetOptimization { possibleTargets.addAll(newPossibleTargets); } + private static Map> createGroups(Game game, Set possibleTargets, int maxPossibleTargetsToSimulate, boolean isLoose) { + Map> targetGroups = new HashMap<>(); + + possibleTargets.forEach(id -> { + String groupKey = ""; + + // player + Player player = game.getPlayer(id); + if (player != null) { + groupKey = getTargetGroupKeyAsPlayer(player); + } + + // game object + MageObject object = game.getObject(id); + if (object != null) { + groupKey = object.getName(); + if (object instanceof Permanent) { + groupKey += getTargetGroupKeyAsPermanent(game, (Permanent) object, isLoose); + } else if (object instanceof Card) { + groupKey += getTargetGroupKeyAsCard(game, (Card) object, isLoose); + } else { + groupKey += getTargetGroupKeyAsOther(game, object); + } + } + + // unknown - use all + if (groupKey.isEmpty()) { + groupKey = id.toString(); + } + + targetGroups.computeIfAbsent(groupKey, k -> new ArrayList<>()).add(id); + }); + + if (targetGroups.size() > maxPossibleTargetsToSimulate && !isLoose) { + // If too many possible target groups, regroup with less specific characteristics + return createGroups(game, possibleTargets, maxPossibleTargetsToSimulate, true); + } + + // Return appropriate target groups or, if still too many possible targets after loose grouping, + // allow optimizePossibleTargets (defined above) to choose random targets within limit + return targetGroups; + } + private static String getTargetGroupKeyAsPlayer(Player player) { // use all return String.join(";", Arrays.asList( @@ -120,38 +128,57 @@ public class TargetOptimization { )); } - private static String getTargetGroupKeyAsPermanent(Game game, Permanent permanent) { + private static String getTargetGroupKeyAsPermanent(Game game, Permanent permanent, boolean isLoose) { // split by name and stats // TODO: rework and combine with PermanentEvaluator (to use battlefield score) // try to use short text/hash for lesser data on debug - return String.join(";", Arrays.asList( - permanent.getName(), - String.valueOf(permanent.getControllerId().hashCode()), - String.valueOf(permanent.getOwnerId().hashCode()), - String.valueOf(permanent.isTapped()), - String.valueOf(permanent.getPower().getValue()), - String.valueOf(permanent.getToughness().getValue()), - String.valueOf(permanent.getDamage()), - String.valueOf(permanent.getCardType(game).toString().hashCode()), - String.valueOf(permanent.getSubtype(game).toString().hashCode()), - String.valueOf(permanent.getCounters(game).getTotalCount()), - String.valueOf(permanent.getAbilities(game).size()), - String.valueOf(permanent.getRules(game).toString().hashCode()) - )); + if (!isLoose) { + return String.join(";", Arrays.asList( + permanent.getName(), + String.valueOf(permanent.getControllerId().hashCode()), + String.valueOf(permanent.getOwnerId().hashCode()), + String.valueOf(permanent.isTapped()), + String.valueOf(permanent.getPower().getValue()), + String.valueOf(permanent.getToughness().getValue()), + String.valueOf(permanent.getDamage()), + String.valueOf(permanent.getCardType(game).toString().hashCode()), + String.valueOf(permanent.getSubtype(game).toString().hashCode()), + String.valueOf(permanent.getCounters(game).getTotalCount()), + String.valueOf(permanent.getAbilities(game).size()), + String.valueOf(permanent.getRules(game).toString().hashCode()) + )); + } + else { + return String.join(";", Arrays.asList( + String.valueOf(permanent.getControllerId().hashCode()), + String.valueOf(permanent.getPower().getValue()), + String.valueOf(permanent.getToughness().getValue()), + String.valueOf(permanent.getDamage()), + String.valueOf(permanent.getCardType(game).toString().hashCode()) + )); + } } - private static String getTargetGroupKeyAsCard(Game game, Card card) { + private static String getTargetGroupKeyAsCard(Game game, Card card, boolean isLoose) { // split by name and stats - return String.join(";", Arrays.asList( - card.getName(), - String.valueOf(card.getOwnerId().hashCode()), - String.valueOf(card.getCardType(game).toString().hashCode()), - String.valueOf(card.getSubtype(game).toString().hashCode()), - String.valueOf(card.getCounters(game).getTotalCount()), - String.valueOf(card.getAbilities(game).size()), - String.valueOf(card.getRules(game).toString().hashCode()) - )); + if (!isLoose) { + return String.join(";", Arrays.asList( + card.getName(), + String.valueOf(card.getOwnerId().hashCode()), + String.valueOf(card.getCardType(game).toString().hashCode()), + String.valueOf(card.getSubtype(game).toString().hashCode()), + String.valueOf(card.getCounters(game).getTotalCount()), + String.valueOf(card.getAbilities(game).size()), + String.valueOf(card.getRules(game).toString().hashCode()) + )); + } + else { + return String.join(";", Arrays.asList( + String.valueOf(card.getOwnerId().hashCode()), + String.valueOf(card.getCardType(game).toString().hashCode()) + )); + } } private static String getTargetGroupKeyAsOther(Game game, MageObject item) { diff --git a/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java b/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java index 8a2661734cc..36824803080 100644 --- a/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java +++ b/Mage/src/main/java/mage/target/common/TargetAttackingCreature.java @@ -21,7 +21,7 @@ public class TargetAttackingCreature extends TargetPermanent { } public TargetAttackingCreature(int minNumTargets, int maxNumTargets, boolean notTarget) { - super(minNumTargets, maxNumTargets, StaticFilters.FILTER_ATTACKING_CREATURE, notTarget); + super(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_ATTACKING_CREATURES : StaticFilters.FILTER_ATTACKING_CREATURE, notTarget); } protected TargetAttackingCreature(final TargetAttackingCreature target) { diff --git a/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java index 3536e38a3f3..bbf6a007bad 100644 --- a/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/EachTargetPointer.java @@ -120,7 +120,9 @@ public class EachTargetPointer extends TargetPointerImpl { @Override public String describeTargets(Targets targets, String defaultDescription) { - if (targetDescription != null) return targetDescription; + if (targetDescription != null) { + return targetDescription; + } if (targets.isEmpty()) { return defaultDescription; } diff --git a/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java b/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java index d4da5b9f329..2cb6e0ebd4d 100644 --- a/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java +++ b/Mage/src/main/java/mage/target/targetpointer/NthTargetPointer.java @@ -148,7 +148,9 @@ public abstract class NthTargetPointer extends TargetPointerImpl { @Override public String describeTargets(Targets targets, String defaultDescription) { - if (targetDescription != null) return targetDescription; + if (targetDescription != null) { + return targetDescription; + } if (targets.size() <= this.targetIndex) { // TODO: need research, is it used for non setup targets ?! // Typical usage example: trigger sets fixed target pointer diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 65a79575a4b..49b4e4e0a73 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -84,7 +84,7 @@ public final class CardUtil { public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS"); private static final List costWords = Arrays.asList( - "put", "return", "exile", "discard", "mill", "sacrifice", "remove", "tap", "reveal", "pay", "have", "collect", "forage" + "put", "return", "exile", "discard", "mill", "sacrifice", "remove", "tap", "reveal", "pay", "have", "collect", "forage", "transform" ); // search set code in commands like "set_code-card_name" @@ -979,7 +979,7 @@ public final class CardUtil { } if (!targetPlayerGets) { sb.append(add ? " on " : " from "); - if (description.contains("up to") && !description.contains("up to one")) { + if (description.contains("any number") || description.contains("up to") && !description.contains("up to one")) { sb.append("each of "); } sb.append(description); @@ -1261,8 +1261,8 @@ public final class CardUtil { permCard = card; } else if (card instanceof CardWithSpellOption) { permCard = card; - } else if (card instanceof ModalDoubleFacedCard) { - permCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); + } else if (card instanceof DoubleFacedCard) { + permCard = ((DoubleFacedCard) card).getLeftHalfCard(); } else { permCard = card; } @@ -1294,8 +1294,8 @@ public final class CardUtil { // it's ok to return one name only cause NamePredicate can find same card by first name if (card instanceof SplitCard) { return ((SplitCard) card).getLeftHalfCard().getName(); - } else if (card instanceof ModalDoubleFacedCard) { - return ((ModalDoubleFacedCard) card).getLeftHalfCard().getName(); + } else if (card instanceof DoubleFacedCard) { + return ((DoubleFacedCard) card).getLeftHalfCard().getName(); } else { return card.getName(); } @@ -1453,6 +1453,9 @@ public final class CardUtil { public static List getCastableComponents(Card cardToCast, FilterCard filter, Ability source, Player player, Game game, SpellCastTracker spellCastTracker, boolean playLand) { UUID playerId = player.getId(); List cards = new ArrayList<>(); + if (cardToCast == null) { + return cards; + } if (cardToCast instanceof CardWithHalves) { cards.add(((CardWithHalves) cardToCast).getLeftHalfCard()); cards.add(((CardWithHalves) cardToCast).getRightHalfCard()); @@ -1536,7 +1539,7 @@ public final class CardUtil { } else { chosenAbility = player.chooseAbilityForCast(cardToCast, game, true); } - boolean result = false; + boolean result; if (chosenAbility instanceof SpellAbility) { result = player.cast( (SpellAbility) chosenAbility, @@ -1545,6 +1548,8 @@ public final class CardUtil { } else if (playLand && chosenAbility instanceof PlayLandAbility) { Card land = game.getCard(chosenAbility.getSourceId()); result = player.playLand(land, game, true); + } else { + result = false; } partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null)); if (result && spellCastTracker != null) { @@ -1667,6 +1672,22 @@ public final class CardUtil { game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), Boolean.TRUE); } + // handle TDFC + if (card instanceof TransformingDoubleFacedCard) { + TransformingDoubleFacedCardHalf frontFace = ((TransformingDoubleFacedCard) card).getLeftHalfCard(); + TransformingDoubleFacedCardHalf backFace = ((TransformingDoubleFacedCard) card).getRightHalfCard(); + + if (manaCost != null) { + // get additional cost if any + Costs additionalCostsMDFCLeft = frontFace.getSpellAbility().getCosts(); + // set alternative cost and any additional cost + player.setCastSourceIdWithAlternateMana(frontFace.getId(), manaCost, additionalCostsMDFCLeft, MageIdentifier.Default); + } + + // allow just the front face + game.getState().setValue("PlayFromNotOwnHandZone" + frontFace.getId(), Boolean.TRUE); + } + // handle adventure cards if (card instanceof CardWithSpellOption) { Card creatureCard = card.getMainCard(); @@ -1704,9 +1725,9 @@ public final class CardUtil { game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null); } - if (card instanceof ModalDoubleFacedCard) { - ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard(); - ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard(); + if (card instanceof DoubleFacedCard) { + DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard(); + DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard(); game.getState().setValue("PlayFromNotOwnHandZone" + leftHalfCard.getId(), null); game.getState().setValue("PlayFromNotOwnHandZone" + rightHalfCard.getId(), null); } @@ -2098,8 +2119,8 @@ public final class CardUtil { res.add(mainCard); res.add(mainCard.getLeftHalfCard()); res.add(mainCard.getRightHalfCard()); - } else if (object instanceof ModalDoubleFacedCard || object instanceof ModalDoubleFacedCardHalf) { - ModalDoubleFacedCard mainCard = (ModalDoubleFacedCard) ((Card) object).getMainCard(); + } else if (object instanceof DoubleFacedCard || object instanceof DoubleFacedCardHalf) { + DoubleFacedCard mainCard = (DoubleFacedCard) ((Card) object).getMainCard(); res.add(mainCard); res.add(mainCard.getLeftHalfCard()); res.add(mainCard.getRightHalfCard()); diff --git a/Mage/src/main/java/mage/util/ManaUtil.java b/Mage/src/main/java/mage/util/ManaUtil.java index f86f376a1d0..c232e4687fb 100644 --- a/Mage/src/main/java/mage/util/ManaUtil.java +++ b/Mage/src/main/java/mage/util/ManaUtil.java @@ -643,8 +643,8 @@ public final class ManaUtil { secondSide = ((SplitCard) card).getRightHalfCard(); } else if (card instanceof CardWithSpellOption) { secondSide = ((CardWithSpellOption) card).getSpellCard(); - } else if (card instanceof ModalDoubleFacedCard) { - secondSide = ((ModalDoubleFacedCard) card).getRightHalfCard(); + } else if (card instanceof DoubleFacedCard) { + secondSide = ((DoubleFacedCard) card).getRightHalfCard(); } else { secondSide = card.getSecondCardFace(); } diff --git a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java index 3b159398037..a53bf0c135f 100644 --- a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java +++ b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java @@ -5,7 +5,7 @@ import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.keyword.PrototypeAbility; -import mage.cards.Card; +import mage.cards.*; import mage.constants.CardType; import mage.constants.SuperType; import mage.game.Game; @@ -91,9 +91,13 @@ public class CopyTokenFunction { copyToToken(target, sourceObj, game); CardUtil.copySetAndCardNumber(target, sourceObj); // second side - if (sourceObj.isTransformable()) { + if (sourceObj.isTransformable() && !(sourceObj instanceof DoubleFacedCardHalf)) { copyToToken(target.getBackFace(), sourceObj.getSecondCardFace(), game); CardUtil.copySetAndCardNumber(target.getBackFace(), sourceObj.getSecondCardFace()); + } else if (sourceObj.isTransformable() && sourceObj instanceof DoubleFacedCardHalf) { + // double faced card + copyToToken(target.getBackFace(), ((DoubleFacedCardHalf) sourceObj).getOtherSide(), game); + CardUtil.copySetAndCardNumber(target.getBackFace(), ((DoubleFacedCardHalf) sourceObj).getOtherSide()); } // apply prototyped status @@ -108,6 +112,35 @@ public class CopyTokenFunction { return; } + // from double faced card spell + if (source instanceof DoubleFacedCardHalf) { + DoubleFacedCardHalf sourceCard = (DoubleFacedCardHalf) source; + Card frontSide; + Card backSide = null; + if (sourceCard.isTransformable()) { + if (sourceCard.isBackSide()) { + target.setEntersTransformed(true); + frontSide = sourceCard.getOtherSide(); + backSide = sourceCard; + } else { + frontSide = sourceCard; + backSide = sourceCard.getOtherSide(); + } + } else { + frontSide = sourceCard; + } + // main side + copyToToken(target, frontSide, game); + target.setCopySourceCard(sourceCard); + CardUtil.copySetAndCardNumber(target, frontSide); + // second side + if (backSide != null) { + copyToToken(target.getBackFace(), backSide, game); + CardUtil.copySetAndCardNumber(target, backSide); + } + return; + } + // from another card (example: Embalm ability) Card sourceObj = CardUtil.getDefaultCardSideForBattlefield(game, source.getMainCard()); target.setCopySourceCard(sourceObj); @@ -121,8 +154,14 @@ public class CopyTokenFunction { // must create back face?? throw new IllegalStateException("Wrong code usage: back face must be non null: " + target.getName() + " - " + target.getClass().getSimpleName()); } - copyToToken(target.getBackFace(), source.getSecondCardFace(), game); - CardUtil.copySetAndCardNumber(target.getBackFace(), source.getSecondCardFace()); + Card secondFace; + if (source instanceof DoubleFacedCard) { + secondFace = ((DoubleFacedCard) source).getRightHalfCard(); + } else { + secondFace = source.getSecondCardFace(); + } + copyToToken(target.getBackFace(), secondFace, game); + CardUtil.copySetAndCardNumber(target.getBackFace(), secondFace); } } diff --git a/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java b/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java deleted file mode 100644 index 17b1d3b18fe..00000000000 --- a/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java +++ /dev/null @@ -1,16 +0,0 @@ -package mage.util.validation; - -import mage.abilities.keyword.PartnerFatherAndSonAbility; -import mage.cards.Card; - -/** - * @author TheElk801 - */ -public enum PartnerFatherAndSonValidator implements CommanderValidator { - instance; - - @Override - public boolean checkPartner(Card commander1, Card commander2) { - return commander1.getAbilities().containsClass(PartnerFatherAndSonAbility.class); - } -} diff --git a/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java b/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java deleted file mode 100644 index 46e086fae85..00000000000 --- a/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java +++ /dev/null @@ -1,16 +0,0 @@ -package mage.util.validation; - -import mage.abilities.keyword.PartnerSurvivorsAbility; -import mage.cards.Card; - -/** - * @author TheElk801 - */ -public enum PartnerSurvivorsValidator implements CommanderValidator { - instance; - - @Override - public boolean checkPartner(Card commander1, Card commander2) { - return commander1.getAbilities().containsClass(PartnerSurvivorsAbility.class); - } -} diff --git a/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java b/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java new file mode 100644 index 00000000000..3084502ab91 --- /dev/null +++ b/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java @@ -0,0 +1,16 @@ +package mage.util.validation; + +import mage.cards.Card; +import mage.constants.PartnerVariantType; + +/** + * @author TheElk801 + */ +public enum PartnerVariantValidator implements CommanderValidator { + instance; + + @Override + public boolean checkPartner(Card commander1, Card commander2) { + return PartnerVariantType.checkCommanders(commander1, commander2); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java index cd5d1681808..a9ef959bb88 100644 --- a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java @@ -5,6 +5,8 @@ import java.util.Map; import java.util.UUID; import mage.MageObject; import mage.cards.Card; +import mage.cards.DoubleFacedCard; +import mage.cards.DoubleFacedCardHalf; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; @@ -36,7 +38,12 @@ public class CommanderInfoWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (checkCommanderDamage && event.getType() == GameEvent.EventType.DAMAGED_PLAYER && event instanceof DamagedPlayerEvent) { - if (sourceId.equals(event.getSourceId())) { + Card sourceCard = game.getCard(event.getSourceId()); + if (sourceCard == null) { + return; + } + sourceCard = sourceCard.getMainCard(); + if (sourceId.equals(sourceCard.getId())) { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; if (damageEvent.isCombatDamage()) { UUID playerUUID = event.getTargetId(); @@ -44,7 +51,7 @@ public class CommanderInfoWatcher extends Watcher { damage += damageEvent.getAmount(); damageToPlayer.put(playerUUID, damage); Player player = game.getPlayer(playerUUID); - MageObject commander = game.getObject(sourceId); + MageObject commander = game.getObject(event.getSourceId()); if (player != null && commander != null) { if (!game.isSimulation()) { game.informPlayers(commander.getLogName() + " did " + damage + " combat damage to " + player.getLogName() + " during the game."); @@ -62,8 +69,15 @@ public class CommanderInfoWatcher extends Watcher { public void addCardInfoToCommander(Game game) { MageObject object = game.getPermanent(sourceId); + MageObject leftObject = null; + MageObject rightObject = null; if (object == null) { object = game.getCard(sourceId); + if (object instanceof DoubleFacedCard) { + DoubleFacedCard cardObject = (DoubleFacedCard)object; + leftObject = game.getPermanent(cardObject.getLeftHalfCard().getId()); + rightObject = game.getPermanent(cardObject.getRightHalfCard().getId()); + } } if (object != null) { StringBuilder sb = new StringBuilder(); @@ -74,6 +88,12 @@ public class CommanderInfoWatcher extends Watcher { sb.append(' ').append(playsCount).append(playsCount == 1 ? " time" : " times").append(" played from the command zone."); } this.addInfoToObject(object, "Commander", sb.toString(), game); + if (leftObject != null) { + this.addInfoToObject(leftObject, "Commander", sb.toString(), game); + } + if (rightObject != null) { + this.addInfoToObject(rightObject, "Commander", sb.toString(), game); + } if (checkCommanderDamage) { for (Map.Entry entry : damageToPlayer.entrySet()) { @@ -81,6 +101,14 @@ public class CommanderInfoWatcher extends Watcher { sb.append("").append(commanderTypeName).append(" did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append('.'); this.addInfoToObject(object, "Commander" + entry.getKey(), "" + commanderTypeName + " did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); + if (leftObject != null) { + this.addInfoToObject(leftObject, "Commander" + entry.getKey(), + "" + commanderTypeName + " did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); + } + if (rightObject != null) { + this.addInfoToObject(object, "Commander" + entry.getKey(), + "" + commanderTypeName + " did " + entry.getValue() + " combat damage to player " + damagedPlayer.getLogName() + '.', game); + } } } } diff --git a/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java b/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java new file mode 100644 index 00000000000..8fb44dac0a0 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/CreatureLeftBattlefieldWatcher.java @@ -0,0 +1,51 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author Susucr + */ +public class CreatureLeftBattlefieldWatcher extends Watcher { + + // player -> number of creatures that left the battlefield under that player's control this turn + private final Map mapCreaturesLeft = new HashMap<>(); + + public CreatureLeftBattlefieldWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ZONE_CHANGE) { + return; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (Zone.BATTLEFIELD.match(zEvent.getFromZone()) && zEvent.getTarget().isCreature(game)) { + mapCreaturesLeft.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + mapCreaturesLeft.clear(); + } + + public static int getNumberCreatureLeft(UUID playerId, Game game) { + return game + .getState() + .getWatcher(CreatureLeftBattlefieldWatcher.class) + .mapCreaturesLeft + .getOrDefault(playerId, 0); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java b/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java index fb3e83d95f0..c6fb4fb1dd5 100644 --- a/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java @@ -44,10 +44,10 @@ public class PermanentsSacrificedWatcher extends Watcher { } public List getThisTurnSacrificedPermanents(UUID playerId) { - return sacrificedPermanents.get(playerId); + return sacrificedPermanents.getOrDefault(playerId, new ArrayList<>()); } public int getThisTurnSacrificedPermanents() { - return sacrificedPermanents.values().stream().mapToInt(permanents -> permanents.size()).sum(); + return sacrificedPermanents.values().stream().mapToInt(List::size).sum(); } } diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index 9875e23e7fc..dd6c10c31d5 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -1515,10 +1515,13 @@ # SLD |Generate|TOK:SLD|Angel|||AngelToken| +|Generate|TOK:SLD|Blood|||BloodToken| |Generate|TOK:SLD|Cat|1||GreenCatToken| |Generate|TOK:SLD|Cat|2||CatToken2| |Generate|TOK:SLD|Cat|3||CatToken2| |Generate|TOK:SLD|Clue|||ClueArtifactToken| +|Generate|TOK:SLD|Cordyceps Infected|1||CordycepsInfectedToken| +|Generate|TOK:SLD|Cordyceps Infected|2||CordycepsInfectedToken| |Generate|TOK:SLD|Dog|||WhiteDogToken| |Generate|TOK:SLD|Egg|||AtlaPalaniToken| |Generate|TOK:SLD|Faerie Rogue|1||FaerieRogueToken| @@ -2782,6 +2785,7 @@ # DSK |Generate|TOK:DSK|Beast|||BeastieToken| +|Generate|TOK:DSK|Demon|||Demon66Token| |Generate|TOK:DSK|Everywhere|||EverywhereToken| |Generate|TOK:DSK|Glimmer|||GlimmerToken| |Generate|TOK:DSK|Gremlin|||Gremlin11Token| @@ -2793,6 +2797,7 @@ |Generate|TOK:DSK|Spider|||Spider22Token| |Generate|TOK:DSK|Spirit|1||Spirit31Token| |Generate|TOK:DSK|Spirit|2||SpiritBlueToken| +|Generate|TOK:DSK|Toy|||ToyToken| |Generate|TOK:DSK|Treasure|||TreasureToken| # FIN @@ -2879,6 +2884,35 @@ |Generate|TOK:SPM|Spider|||Spider21Token| |Generate|TOK:SPM|Treasure|||TreasureToken| +#TLA +|Generate|TOK:TLA|Ally|1||AllyToken| +|Generate|TOK:TLA|Ally|2||AllyToken| +|Generate|TOK:TLA|Ally|3||AllyToken| +|Generate|TOK:TLA|Ally|4||AllyToken| +|Generate|TOK:TLA|Ally|5||AllyToken| +|Generate|TOK:TLA|Ballistic Boulder|||BallisticBoulder| +|Generate|TOK:TLA|Bear|||BearsCompanionBearToken| +|Generate|TOK:TLA|Clue|1||ClueArtifactToken| +|Generate|TOK:TLA|Clue|2||ClueArtifactToken| +|Generate|TOK:TLA|Clue|3||ClueArtifactToken| +|Generate|TOK:TLA|Clue|4||ClueArtifactToken| +|Generate|TOK:TLA|Clue|5||ClueArtifactToken| +|Generate|TOK:TLA|Dragon|||DragonFirebendingToken| +|Generate|TOK:TLA|Food|1||FoodToken| +|Generate|TOK:TLA|Food|2||FoodToken| +|Generate|TOK:TLA|Food|3||FoodToken| +|Generate|TOK:TLA|Monk|||MonkRedToken| +|Generate|TOK:TLA|Soldier|||SoldierFirebendingToken| +|Generate|TOK:TLA|Spirit|||SpiritWorldToken| +|Generate|TOK:TLA|Treasure|||TreasureToken| + +#TLE +|Generate|TOK:TLE|Marit Lage|||MaritLageToken| +|Generate|TOK:TLE|Soldier|||SoldierRedToken| + +#TMT +|Generate|TOK:TMT|Mutagen|||MutagenToken| + # JVC |Generate|TOK:JVC|Elemental Shaman|||ElementalShamanToken| @@ -2956,4 +2990,4 @@ |Generate|TOK:PL24|Dragon|||DragonToken| # PL25 -|Generate|TOK:PL25|Snake|||SnakeToken| \ No newline at end of file +|Generate|TOK:PL25|Snake|||SnakeToken| diff --git a/Utils/cardInfo.tmpl b/Utils/cardInfo.tmpl index 5b04c6a01b1..c0f7b5013a5 100644 --- a/Utils/cardInfo.tmpl +++ b/Utils/cardInfo.tmpl @@ -2,6 +2,6 @@ [=$cardName=] [=$manaCost=] [=$typeLine=] - [=$abilities=][= $powerToughness ? "\n $powerToughness" : "" =] + [=$abilities=][=$loyalty ? "\n Loyalty:$loyalty" : "" =][=$powerToughness ? "\n $powerToughness" : "" =] */ private static final String [=$classNameLower=] = "[=$cardName=]"; \ No newline at end of file diff --git a/Utils/cardSplitClass.tmpl b/Utils/cardSplitClass.tmpl index c9d9200ba43..bea55bfc800 100644 --- a/Utils/cardSplitClass.tmpl +++ b/Utils/cardSplitClass.tmpl @@ -3,7 +3,7 @@ package mage.cards.[=$cardNameFirstLetter=]; import java.util.UUID; [=$abilitiesImports=] import mage.cards.CardSetInfo; -import mage.cards.SplitCard; +import mage.cards.RoomCard; import mage.constants.CardType; import mage.constants.SpellAbilityType; @@ -11,17 +11,13 @@ import mage.constants.SpellAbilityType; * * @author [=$author=] */ -public final class [=$className=] extends SplitCard { +public final class [=$className=] extends RoomCard { + public [=$className=](UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{[=$type=]}, new CardType[]{??}, "[=$manaCost=]", "??", SpellAbilityType.SPLIT_AFTERMATH); - [=$subType=][=$colors=] + super(ownerId, setInfo, "[=$manaCost=]"); [= if ($power || $power eq 0) { $OUT .= "\n this.power = new MageInt($power);"; $OUT .= "\n this.toughness = new MageInt($toughness);";} =][=$abilities=] - // getLeftHalfCard().getSpellAbility().addEffect(new Effect()); - - // getRightHalfCard().getSpellAbility().addEffect(new Effect()); - } private [=$className=](final [=$className=] card) { diff --git a/Utils/gen-card-test.pl b/Utils/gen-card-test.pl old mode 100644 new mode 100755 index 1817ed3a63f..152f5ec8aa3 --- a/Utils/gen-card-test.pl +++ b/Utils/gen-card-test.pl @@ -11,7 +11,6 @@ You can add as many additional cards as you like. You can also call the script without arguments and it will prompt you for card names =cut - use Text::Template; use strict; use File::Path qw(make_path); @@ -40,12 +39,87 @@ sub fixCost { $string; } +# Resolve a user-provided card name to the canonical card key in %cards. +# Tries: +# 1) exact key +# 2) case-insensitive exact match +# 3) case-insensitive substring match (if single match => use it, if multiple => warn and return undef) +sub resolveCardName { + my ($input) = @_; + return undef unless defined $input; + # trim whitespace + $input =~ s/^\s+|\s+$//g; + return $input if exists $cards{$input}; + + my $lc_input = lc $input; + + # case-insensitive exact + foreach my $k (keys %cards) { + return $k if lc($k) eq $lc_input; + } + + # substring (partial) matches + my @matches = grep { index(lc($_), $lc_input) != -1 } keys %cards; + if (@matches == 1) { + return $matches[0]; + } elsif (@matches > 1) { + @matches = sort @matches; + # If not interactive, don't block; print candidates and return undef + unless (-t STDIN) { + warn "Multiple matches found for '$input' (non-interactive):\n"; + foreach my $m (@matches) { warn " $m\n"; } + warn "Please be more specific.\n"; + return undef; + } + + print "Multiple matches found for '$input':\n"; + my $i = 0; + foreach my $m (@matches) { + $i++; + print " $i) $m\n"; + } + + while (1) { + print "Select a number (1-$i) or 0 to cancel: "; + my $choice = ; + unless (defined $choice) { print "\nNo selection (EOF). Skipping.\n"; return undef; } + chomp $choice; + $choice =~ s/^\s+|\s+$//g; + + # numeric choice + if ($choice =~ /^\d+$/) { + my $num = int($choice); + if ($num == 0) { + return undef; + } elsif ($num >= 1 && $num <= $i) { + return $matches[$num - 1]; + } + } else { + # try exact name match among candidates (case-insensitive) + foreach my $m (@matches) { + return $m if lc($m) eq lc($choice); + } + } + + print "Invalid selection, please try again.\n"; + } + } + + return undef; +} + + sub generateCardInfo { my ($cardName, $infoTemplate) = @_; + # attempt to resolve loosely if direct lookup fails if (!exists $cards{$cardName}) { - warn "Card name doesn't exist: $cardName (skipping)\n"; - return ""; + my $resolved = resolveCardName($cardName); + if (!defined $resolved) { + warn "Card name doesn't exist: $cardName (skipping)\n"; + return ""; + } + $cardName = $resolved; } my %vars; @@ -61,17 +135,30 @@ sub generateCardInfo { $vars{'manaCost'} = $card[4]; $vars{'typeLine'} = $card[5]; - my $cardAbilities = $card[8]; + # Check if this is a planeswalker + my $isPlaneswalker = $card[5] =~ /Planeswalker/i; + + my $cardAbilities; + if ($isPlaneswalker) { + # For planeswalkers: field 6 is loyalty, field 7 is abilities + $vars{'loyalty'} = $card[6] if $card[6]; # loyalty + $cardAbilities = $card[7]; + } else { + # For non-planeswalkers: field 6/7 is power/toughness, field 8 is abilities + if ($card[6]) { + $vars{'powerToughness'} = "$card[6]/$card[7]"; + } + $cardAbilities = $card[8]; + } + my @abilities = split(/\$/, $cardAbilities); my $abilitiesFormatted = join("\n ", @abilities); $vars{'abilities'} = $abilitiesFormatted; - if ($card[6]) { - $vars{'powerToughness'} = "$card[6]/$card[7]" - } return $infoTemplate->fill_in(HASH => \%vars); } + my $author; if (-e $authorFile) { open(DATA, $authorFile) || die "can't open $authorFile : $!"; @@ -110,7 +197,7 @@ while (my $line = ) { } close(DATA); -# Get card names from arguments +# Get card names from arguments or prompt my @cardNames = @ARGV; if (@cardNames == 0) { print 'Enter a card name: '; @@ -127,17 +214,27 @@ if (@cardNames == 0) { } } +# Trim whitespace for all inputs +foreach my $i (0..$#cardNames) { + $cardNames[$i] =~ s/^\s+|\s+$//g if defined $cardNames[$i]; +} + # Main card is the first one -my $mainCardName = $cardNames[0]; -my @additionalCards = @cardNames[1..$#cardNames]; +my $mainCardNameInput = $cardNames[0]; + +# Resolve main card with loose matching +my $resolvedMain = resolveCardName($mainCardNameInput); +if (!defined $resolvedMain) { + die "Card name doesn't exist or is ambiguous: $mainCardNameInput\n"; +} +my $mainCardName = $resolvedMain; + +my @additionalCardsInput = (); +if (@cardNames > 1) { + @additionalCardsInput = @cardNames[1..$#cardNames]; +} if (!exists $cards{$mainCardName}) { - my $possible; - foreach $possible (sort keys(%cards)) { - if ($possible =~ m/$mainCardName/img && $mainCardName =~ m/..../) { - print("Did you mean $possible?\n"); - } - } die "Card name doesn't exist: $mainCardName\n"; } @@ -153,7 +250,17 @@ $vars{'classNameLower'} = lcfirst(toCamelCase($mainCardName)); $vars{'cardNameFirstLetter'} = lc substr($mainCardName, 0, 1); foreach my $setName (keys %{$cards{$originalName}}) { - $setCode = lc($sets{$setName}); + if (exists $sets{$setName}) { + $setCode = lc($sets{$setName}); + last; # Use the first valid set found + } +} + +# Fallback if no valid set code was found +unless (defined $setCode) { + warn "Warning: No valid set code found for card '$mainCardName'. Using 'unk' as fallback.\n"; + warn "Available sets for this card: " . join(", ", keys %{$cards{$originalName}}) . "\n"; + $setCode = 'unk'; } # Check if card is already implemented @@ -177,10 +284,15 @@ $vars{'setCode'} = $setCode; # Generate main card info my $allCardInfo = generateCardInfo($mainCardName, $infoTemplate); -# Generate additional card info templates -foreach my $additionalCard (@additionalCards) { - my $additionalInfo = generateCardInfo($additionalCard, $infoTemplate); - if (defined $additionalInfo) { +# Generate additional card info templates (resolve each loosely) +foreach my $additionalCardInput (@additionalCardsInput) { + my $resolved = resolveCardName($additionalCardInput); + if (!defined $resolved) { + warn "Skipping additional card (not found or ambiguous): $additionalCardInput\n"; + next; + } + my $additionalInfo = generateCardInfo($resolved, $infoTemplate); + if (defined $additionalInfo && $additionalInfo ne '') { $allCardInfo .= "\n\n" . $additionalInfo; } } @@ -193,6 +305,6 @@ print CARD $result; close CARD; print "$fileName\n"; -if (@additionalCards > 0) { - print "Additional cards included: " . join(", ", @additionalCards) . "\n"; +if (@additionalCardsInput > 0) { + print "Additional cards included: " . join(", ", map { resolveCardName($_) // $_ } @additionalCardsInput) . "\n"; } \ No newline at end of file diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 84f79af28cb..7dfe18852cc 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -20,6 +20,7 @@ sub toCamelCase { my $string = $_[0]; $string =~ s/\b([\w']+)\b/ucfirst($1)/ge; $string =~ s/[-,\s\':.!\/]//g; + $string =~ s/\&/And/g; $string; } diff --git a/Utils/keywords.txt b/Utils/keywords.txt index a2e1ccb4ebe..84b42818d1a 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -126,6 +126,7 @@ Shroud|instance| Soulbond|new| Soulshift|number| Skulk|new| +Sneak|card, manaString| Spectacle|card, cost| Spree|card| Squad|cost| diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 48fa4e4a535..aee325dffed 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -191,6 +191,8 @@ Media Inserts|MediaInserts| March of the Machine|MarchOfTheMachine| March of the Machine Commander|MarchOfTheMachineCommander| March of the Machine: The Aftermath|MarchOfTheMachineTheAftermath| +Marvel Super Heroes|MarvelSuperHeroes| +Marvel Super Heroes Commander|MarvelSuperHeroesCommander| Mercadian Masques|MercadianMasques| Mirage|Mirage| Mirrodin|Mirrodin| @@ -242,7 +244,7 @@ Sega Dreamcast Cards|SegaDreamcastCards| Scars of Mirrodin|ScarsOfMirrodin| Scourge|Scourge| Secret Lair Drop|SecretLairDrop| -Secret Lair Showdown|SecretLairShowdown| +Secret Lair Promo|SecretLairPromo| Seventh Edition|SeventhEdition| Shadowmoor|Shadowmoor| Shadows over Innistrad|ShadowsOverInnistrad| @@ -259,6 +261,8 @@ Stronghold|Stronghold| Super Series|SuperSeries| Tarkir: Dragonstorm|TarkirDragonstorm| Tarkir: Dragonstorm Commander|TarkirDragonstormCommander| +Teenage Mutant Ninja Turtles|TeenageMutantNinjaTurtles| +Teenage Mutant Ninja Turtles Eternal|TeenageMutantNinjaTurtlesEternal| Tempest|Tempest| Tempest Remastered|TempestRemastered| Tenth Edition|TenthEdition| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 7f3a4737703..41952ffe63c 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -53982,8 +53982,8 @@ Forceful Cultivator|Alchemy: Kamigawa|29|M|{2}{G}{G}|Creature - Snake Shaman|2|3 Imperial Blademaster|Alchemy: Kamigawa|30|R|{1}{R}{W}|Creature - Human Samurai|2|3|Double strike$Whenever a Samurai or Warrior you control attacks alone, draft a card from Imperial Blademaster's spellbook.| Acrobatic Cheerleader|Duskmourn: House of Horror|1|C|{1}{W}|Creature - Human Survivor|2|2|Survival -- At the beginning of your second main phase, if this creature is tapped, put a flying counter on it. This ability triggers only once.| Cult Healer|Duskmourn: House of Horror|2|C|{2}{W}|Creature - Human Doctor|3|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, this creature gains lifelink until end of turn.| -Dazzling Theater // Prop Room|Duskmourn: House of Horror|3|R|{3}{W}|Enchantment - Room|||Creature spells you cast have convoke.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Prop Room${2}{W}$Enchantment -- Room$Untap each creature you control during each other player's untap step.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|4|M|{1}{W}|Enchantment - Room|||Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Porcelain Gallery${4}{W}{W}$Enchantment -- Room$Creatures you control have base power and toughness each equal to the number of creatures you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Dazzling Theater // Prop Room|Duskmourn: House of Horror|3|R|{3}{W}","{2}{W}|Enchantment - Room|||Dazzling Theater$Creature spells you cast have convoke.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Prop Room$Enchantment -- Room$Untap each creature you control during each other player's untap step.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|4|M|{1}{W}","{4}{W}{W}|Enchantment - Room|||Dollmaker's Shop$Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Porcelain Gallery$Enchantment -- Room$Creatures you control have base power and toughness each equal to the number of creatures you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Emerge from the Cocoon|Duskmourn: House of Horror|5|C|{4}{W}|Sorcery|||Return target creature card from your graveyard to the battlefield. You gain 3 life.| Enduring Innocence|Duskmourn: House of Horror|6|R|{1}{W}{W}|Enchantment Creature - Sheep Glimmer|2|1|Lifelink$Whenever one or more other creatures you control with power 2 or less enter, draw a card. This ability triggers only once each turn.$When Enduring Innocence dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| Ethereal Armor|Duskmourn: House of Horror|7|U|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each enchantment you control and has first strike.| @@ -53994,7 +53994,7 @@ Fear of Surveillance|Duskmourn: House of Horror|11|C|{1}{W}|Enchantment Creature Friendly Ghost|Duskmourn: House of Horror|12|C|{3}{W}|Creature - Spirit|2|4|Flying$When this creature enters, target creature gets +2/+4 until end of turn.| Ghostly Dancers|Duskmourn: House of Horror|13|R|{3}{W}{W}|Creature - Spirit|2|5|Flying$When this creature enters, return an enchantment card from your graveyard to your hand or unlock a locked door of a Room you control.$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 3/1 white Spirit creature token with flying.| Glimmer Seeker|Duskmourn: House of Horror|14|U|{2}{W}|Creature - Human Survivor|3|3|Survival -- At the beginning of your second main phase, if this creature is tapped, draw a card if you control a Glimmer creature. If you don't control a Glimmer creature, create a 1/1 white Glimmer enchantment creature token.| -Grand Entryway // Elegant Rotunda|Duskmourn: House of Horror|15|C|{1}{W}|Enchantment - Room|||When you unlock this door, create a 1/1 white Glimmer enchantment creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Elegant Rotunda${2}{W}$Enchantment -- Room$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Grand Entryway // Elegant Rotunda|Duskmourn: House of Horror|15|C|{1}{W}","{2}{W}|Enchantment - Room|||Grand Entryway$When you unlock this door, create a 1/1 white Glimmer enchantment creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Elegant Rotunda$Enchantment -- Room$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Hardened Escort|Duskmourn: House of Horror|16|C|{2}{W}|Creature - Human Soldier|2|4|Whenever this creature attacks, another target creature you control gets +1/+0 and gains indestructible until end of turn.| Jump Scare|Duskmourn: House of Horror|17|C|{W}|Instant|||Until end of turn, target creature gets +2/+2, gains flying, and becomes a Horror enchantment creature in addition to its other types.| Leyline of Hope|Duskmourn: House of Horror|18|R|{2}{W}{W}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$If you would gain life, you gain that much life plus 1 instead.$As long as you have at least 7 life more than your starting life total, creatures you control get +2/+2.| @@ -54013,7 +54013,7 @@ Sheltered by Ghosts|Duskmourn: House of Horror|30|U|{1}{W}|Enchantment - Aura||| Shepherding Spirits|Duskmourn: House of Horror|31|C|{4}{W}{W}|Creature - Spirit|4|5|Flying$Plainscycling {2}| Split Up|Duskmourn: House of Horror|32|R|{1}{W}{W}|Sorcery|||Choose one --$* Destroy all tapped creatures.$* Destroy all untapped creatures.| Splitskin Doll|Duskmourn: House of Horror|33|U|{1}{W}|Artifact Creature - Toy|2|1|When this creature enters, draw a card. Then discard a card unless you control another creature with power 2 or less.| -Surgical Suite // Hospital Room|Duskmourn: House of Horror|34|U|{1}{W}|Enchantment - Room|||When you unlock this door, return target creature card with mana value 3 or less from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Hospital Room${3}{W}$Enchantment -- Room$Whenever you attack, put a +1/+1 counter on target attacking creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Surgical Suite // Hospital Room|Duskmourn: House of Horror|34|U|{1}{W}","{3}{W}|Enchantment - Room|||Surgical Suite$When you unlock this door, return target creature card with mana value 3 or less from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Hospital Room$Enchantment -- Room$Whenever you attack, put a +1/+1 counter on target attacking creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Toby, Beastie Befriender|Duskmourn: House of Horror|35|R|{2}{W}|Legendary Creature - Human Wizard|1|1|When Toby enters, create a 4/4 white Beast creature token with "This token can't attack or block alone."$As long as you control four or more creature tokens, creature tokens you control have flying.| Trapped in the Screen|Duskmourn: House of Horror|36|C|{2}{W}|Enchantment|||Ward {2}$When this enchantment enters, exile target artifact, creature, or enchantment an opponent controls until this enchantment leaves the battlefield.| Unidentified Hovership|Duskmourn: House of Horror|37|R|{1}{W}{W}|Artifact - Vehicle|2|2|Flying$When this Vehicle enters, exile up to one target creature with toughness 5 or less.$When this Vehicle leaves the battlefield, the exiled card's owner manifests dread.$Crew 1| @@ -54022,8 +54022,8 @@ Unwanted Remake|Duskmourn: House of Horror|39|U|{W}|Instant|||Destroy target cre Veteran Survivor|Duskmourn: House of Horror|40|U|{W}|Creature - Human Survivor|2|1|Survival -- At the beginning of your second main phase, if this creature is tapped, exile up to one target card from a graveyard.$As long as there are three or more cards exiled with this creature, it gets +3/+3 and has hexproof.| The Wandering Rescuer|Duskmourn: House of Horror|41|M|{3}{W}{W}|Legendary Creature - Human Samurai Noble|3|4|Flash$Convoke$Double strike$Other tapped creatures you control have hexproof.| Abhorrent Oculus|Duskmourn: House of Horror|42|M|{2}{U}|Creature - Eye|5|5|As an additional cost to cast this spell, exile six cards from your graveyard.$Flying$At the beginning of each opponent's upkeep, manifest dread.| -Bottomless Pool // Locker Room|Duskmourn: House of Horror|43|U|{U}|Enchantment - Room|||When you unlock this door, return up to one target creature to its owner's hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Locker Room${4}{U}$Enchantment -- Room$Whenever one or more creatures you control deal combat damage to a player, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Central Elevator // Promising Stairs|Duskmourn: House of Horror|44|R|{3}{U}|Enchantment - Room|||When you unlock this door, search your library for a Room card that doesn't have the same name as a Room you control, reveal it, put it into your hand, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Promising Stairs${2}{U}$Enchantment -- Room$At the beginning of your upkeep, surveil 1. You win the game if there are eight or more different names among unlocked doors of Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Bottomless Pool // Locker Room|Duskmourn: House of Horror|43|U|{U}","{4}{U}|Enchantment - Room|||Bottomless Pool$When you unlock this door, return up to one target creature to its owner's hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Locker Room$Enchantment -- Room$Whenever one or more creatures you control deal combat damage to a player, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Central Elevator // Promising Stairs|Duskmourn: House of Horror|44|R|{3}{U}","{2}{U}|Enchantment - Room|||Central Elevator$When you unlock this door, search your library for a Room card that doesn't have the same name as a Room you control, reveal it, put it into your hand, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Promising Stairs$Enchantment -- Room$At the beginning of your upkeep, surveil 1. You win the game if there are eight or more different names among unlocked doors of Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Clammy Prowler|Duskmourn: House of Horror|45|C|{3}{U}|Enchantment Creature - Horror|2|5|Whenever this creature attacks, another target attacking creature can't be blocked this turn.| Creeping Peeper|Duskmourn: House of Horror|46|C|{1}{U}|Creature - Eye|2|1|{T}: Add {U}. Spend this mana only to cast an enchantment spell, unlock a door, or turn a permanent face up.| Cursed Windbreaker|Duskmourn: House of Horror|47|U|{2}{U}|Artifact - Equipment|||When this Equipment enters, manifest dread, then attach this Equipment to that creature.$Equipped creature has flying.$Equip {3}| @@ -54044,9 +54044,9 @@ Ghostly Keybearer|Duskmourn: House of Horror|61|U|{3}{U}|Creature - Spirit|3|3|F Glimmerburst|Duskmourn: House of Horror|62|C|{3}{U}|Instant|||Draw two cards. Create a 1/1 white Glimmer enchantment creature token.| Leyline of Transformation|Duskmourn: House of Horror|63|R|{2}{U}{U}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$As this enchantment enters, choose a creature type.$Creatures you control are the chosen type in addition to their other types. The same is true for creature spells you control and creature cards you own that aren't on the battlefield.| Marina Vendrell's Grimoire|Duskmourn: House of Horror|64|R|{5}{U}|Legendary Artifact|||When Marina Vendrell's Grimoire enters, if you cast it, draw five cards.$You have no maximum hand size and don't lose the game for having 0 or less life.$Whenever you gain life, draw that many cards.$Whenever you lose life, discard that many cards. Then if you have no cards in hand, you lose the game.| -Meat Locker // Drowned Diner|Duskmourn: House of Horror|65|C|{2}{U}|Enchantment - Room|||When you unlock this door, tap up to one target creature and put two stun counters on it.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Drowned Diner${3}{U}{U}$Enchantment -- Room$When you unlock this door, draw three cards, then discard a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Meat Locker // Drowned Diner|Duskmourn: House of Horror|65|C|{2}{U}","{3}{U}{U}|Enchantment - Room|||Meat Locker$When you unlock this door, tap up to one target creature and put two stun counters on it.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Drowned Diner$Enchantment -- Room$When you unlock this door, draw three cards, then discard a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| The Mindskinner|Duskmourn: House of Horror|66|R|{U}{U}{U}|Legendary Enchantment Creature - Nightmare|10|1|The Mindskinner can't be blocked.$If a source you control would deal damage to an opponent, prevent that damage and each opponent mills that many cards.| -Mirror Room // Fractured Realm|Duskmourn: House of Horror|67|M|{2}{U}|Enchantment - Room|||When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Fractured Realm${5}{U}{U}$Enchantment -- Room$If a triggered ability of a permanent you control triggers, that ability triggers an additional time.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Mirror Room // Fractured Realm|Duskmourn: House of Horror|67|M|{2}{U}","{5}{U}{U}|Enchantment - Room|||Mirror Room$When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Fractured Realm$Enchantment -- Room$If a triggered ability of a permanent you control triggers, that ability triggers an additional time.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Overlord of the Floodpits|Duskmourn: House of Horror|68|M|{3}{U}{U}|Enchantment Creature - Avatar Horror|5|3|Impending 4--{1}{U}{U}$Flying$Whenever this permanent enters or attacks, draw two cards, then discard a card.| Paranormal Analyst|Duskmourn: House of Horror|69|U|{1}{U}|Creature - Human Detective|1|3|Whenever you manifest dread, put a card you put into your graveyard this way into your hand.| Piranha Fly|Duskmourn: House of Horror|70|C|{1}{U}|Creature - Fish Insect|2|1|Flying$This creature enters tapped.| @@ -54058,7 +54058,7 @@ The Tale of Tamiyo|Duskmourn: House of Horror|75|R|{2}{U}|Legendary Enchantment Tunnel Surveyor|Duskmourn: House of Horror|76|C|{2}{U}|Creature - Human Detective|2|2|When this creature enters, create a 1/1 white Glimmer enchantment creature token.| Twist Reality|Duskmourn: House of Horror|77|C|{1}{U}{U}|Instant|||Choose one --$* Counter target spell.$* Manifest dread.| Unable to Scream|Duskmourn: House of Horror|78|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature loses all abilities and is a Toy artifact creature with base power and toughness 0/2 in addition to its other types.$As long as enchanted creature is face down, it can't be turned face up.| -Underwater Tunnel // Slimy Aquarium|Duskmourn: House of Horror|79|C|{U}|Enchantment - Room|||When you unlock this door, surveil 2.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Slimy Aquarium${3}{U}$Enchantment -- Room$When you unlock this door, manifest dread, then put a +1/+1 counter on that creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Underwater Tunnel // Slimy Aquarium|Duskmourn: House of Horror|79|C|{U}","{3}{U}|Enchantment - Room|||Underwater Tunnel$When you unlock this door, surveil 2.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Slimy Aquarium$Enchantment -- Room$When you unlock this door, manifest dread, then put a +1/+1 counter on that creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Unnerving Grasp|Duskmourn: House of Horror|80|U|{2}{U}|Sorcery|||Return up to one target nonland permanent to its owner's hand. Manifest dread.| Unwilling Vessel|Duskmourn: House of Horror|81|U|{2}{U}|Creature - Human Wizard|3|2|Vigilance$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, put a possession counter on this creature.$When this creature dies, create an X/X blue Spirit creature token with flying, where X is the number of counters on this creature.| Vanish from Sight|Duskmourn: House of Horror|82|C|{3}{U}|Instant|||Target nonland permanent's owner puts it on their choice of the top or bottom of their library. Surveil 1.| @@ -54070,16 +54070,16 @@ Commune with Evil|Duskmourn: House of Horror|87|U|{2}{B}|Sorcery|||Look at the t Cracked Skull|Duskmourn: House of Horror|88|C|{2}{B}|Enchantment - Aura|||Enchant creature$When this Aura enters, look at target player's hand. You may choose a nonland card from it. That player discards that card.$When enchanted creature is dealt damage, destroy it.| Cynical Loner|Duskmourn: House of Horror|89|U|{1}{B}|Creature - Human Survivor|3|1|This creature can't be blocked by Glimmers.$Survival -- At the beginning of your second main phase, if this creature is tapped, you may search your library for a card, put it into your graveyard, then shuffle.| Dashing Bloodsucker|Duskmourn: House of Horror|90|U|{3}{B}|Creature - Vampire Warrior|2|5|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, this creature gets +2/+0 and gains lifelink until end of turn.| -Defiled Crypt // Cadaver Lab|Duskmourn: House of Horror|91|U|{3}{B}|Enchantment - Room|||Whenever one or more cards leave your graveyard, create a 2/2 black Horror enchantment creature token. This ability triggers only once each turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Cadaver Lab${B}$Enchantment -- Room$When you unlock this door, return target creature card from your graveyard to your hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Defiled Crypt // Cadaver Lab|Duskmourn: House of Horror|91|U|{3}{B}","{B}|Enchantment - Room|||Defiled Crypt$Whenever one or more cards leave your graveyard, create a 2/2 black Horror enchantment creature token. This ability triggers only once each turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Cadaver Lab$Enchantment -- Room$When you unlock this door, return target creature card from your graveyard to your hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Demonic Counsel|Duskmourn: House of Horror|92|R|{1}{B}|Sorcery|||Search your library for a Demon 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 any card, put it into your hand, then shuffle.| -Derelict Attic // Widow's Walk|Duskmourn: House of Horror|93|C|{2}{B}|Enchantment - Room|||When you unlock this door, you draw two cards and you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Widow's Walk${3}{B}$Enchantment -- Room$Whenever a creature you control attacks alone, it gets +1/+0 and gains deathtouch until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Derelict Attic // Widow's Walk|Duskmourn: House of Horror|93|C|{2}{B}","{3}{B}|Enchantment - Room|||Derelict Attic$When you unlock this door, you draw two cards and you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Widow's Walk$Enchantment -- Room$Whenever a creature you control attacks alone, it gets +1/+0 and gains deathtouch until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Doomsday Excruciator|Duskmourn: House of Horror|94|R|{B}{B}{B}{B}{B}{B}|Creature - Demon|6|6|Flying$When this creature enters, if it was cast, each player exiles all but the bottom six cards of their library face down.$At the beginning of your upkeep, draw a card.| Enduring Tenacity|Duskmourn: House of Horror|95|R|{2}{B}{B}|Enchantment Creature - Snake Glimmer|4|3|Whenever you gain life, target opponent loses that much life.$When Enduring Tenacity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.| Fanatic of the Harrowing|Duskmourn: House of Horror|96|C|{3}{B}|Creature - Human Cleric|2|2|When this creature enters, each player discards a card. If you discarded a card this way, draw a card.| Fear of Lost Teeth|Duskmourn: House of Horror|97|C|{B}|Enchantment Creature - Nightmare|1|1|When this creature dies, it deals 1 damage to any target and you gain 1 life.| Fear of the Dark|Duskmourn: House of Horror|98|C|{4}{B}|Enchantment Creature - Nightmare|5|5|Whenever this creature attacks, if defending player controls no Glimmer creatures, it gains menace and deathtouch until end of turn.| Final Vengeance|Duskmourn: House of Horror|99|C|{B}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature or enchantment.$Exile target creature.| -Funeral Room // Awakening Hall|Duskmourn: House of Horror|100|M|{2}{B}|Enchantment - Room|||Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Awakening Hall${6}{B}{B}$Enchantment -- Room$When you unlock this door, return all creature cards from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Funeral Room // Awakening Hall|Duskmourn: House of Horror|100|M|{2}{B}","{6}{B}{B}|Enchantment - Room|||Funeral Room$Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Awakening Hall$Enchantment -- Room$When you unlock this door, return all creature cards from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Give In to Violence|Duskmourn: House of Horror|101|C|{1}{B}|Instant|||Target creature gets +2/+2 and gains lifelink until end of turn.| Grievous Wound|Duskmourn: House of Horror|102|R|{3}{B}{B}|Enchantment - Aura|||Enchant player$Enchanted player can't gain life.$Whenever enchanted player is dealt damage, they lose half their life, rounded up.| Innocuous Rat|Duskmourn: House of Horror|103|C|{1}{B}|Creature - Rat|1|1|When this creature dies, manifest dread.| @@ -54097,7 +54097,7 @@ Popular Egotist|Duskmourn: House of Horror|114|U|{2}{B}|Creature - Human Rogue|3 Resurrected Cultist|Duskmourn: House of Horror|115|C|{2}{B}|Creature - Human Cleric|4|1|Delirium -- {2}{B}{B}: Return this card from your graveyard to the battlefield with a finality counter on it. Activate only if there are four or more card types among cards in your graveyard and only as a sorcery.| Spectral Snatcher|Duskmourn: House of Horror|116|C|{4}{B}{B}|Creature - Spirit|6|5|Ward--Discard a card.$Swampcycling {2}| Sporogenic Infection|Duskmourn: House of Horror|117|U|{1}{B}|Enchantment - Aura|||Enchant creature$When this Aura enters, target player sacrifices a creature of their choice other than enchanted creature.$When enchanted creature is dealt damage, destroy it.| -Unholy Annex // Ritual Chamber|Duskmourn: House of Horror|118|R|{2}{B}|Enchantment - Room|||At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Ritual Chamber${3}{B}{B}$Enchantment -- Room$When you unlock this door, create a 6/6 black Demon creature token with flying.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Unholy Annex // Ritual Chamber|Duskmourn: House of Horror|118|R|{2}{B}","{3}{B}{B}|Enchantment - Room|||Unholy Annex$At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Ritual Chamber$Enchantment -- Room$When you unlock this door, create a 6/6 black Demon creature token with flying.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Unstoppable Slasher|Duskmourn: House of Horror|119|R|{2}{B}|Creature - Zombie Assassin|2|3|Deathtouch$Whenever this creature deals combat damage to a player, they lose half their life, rounded up.$When this creature dies, if it had no counters on it, return it to the battlefield tapped under its owner's control with two stun counters on it.| Valgavoth, Terror Eater|Duskmourn: House of Horror|120|M|{6}{B}{B}{B}|Legendary Creature - Elder Demon|9|9|Flying, lifelink$Ward--Sacrifice three nonland permanents.$If a card you didn't control would be put into an opponent's graveyard from anywhere, exile it instead.$During your turn, you may play cards exiled with Valgavoth. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.| Valgavoth's Faithful|Duskmourn: House of Horror|121|U|{B}|Creature - Human Cleric|1|1|{3}{B}, Sacrifice this creature: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery.| @@ -54108,7 +54108,7 @@ Bedhead Beastie|Duskmourn: House of Horror|125|C|{4}{R}{R}|Creature - Beast|5|6| Betrayer's Bargain|Duskmourn: House of Horror|126|U|{1}{R}|Instant|||As an additional cost to cast this spell, sacrifice a creature or enchantment or pay {2}.$Betrayer's Bargain deals 5 damage to target creature. If that creature would die this turn, exile it instead.| Boilerbilges Ripper|Duskmourn: House of Horror|127|C|{4}{R}|Creature - Human Assassin|4|4|When this creature enters, you may sacrifice another creature or enchantment. When you do, this creature deals 2 damage to any target.| Chainsaw|Duskmourn: House of Horror|128|R|{1}{R}|Artifact - Equipment|||When this Equipment enters, it deals 3 damage to up to one target creature.$Whenever one or more creatures die, put a rev counter on this Equipment.$Equipped creature gets +X/+0, where X is the number of rev counters on this Equipment.$Equip {3}| -Charred Foyer // Warped Space|Duskmourn: House of Horror|129|M|{3}{R}|Enchantment - Room|||At the beginning of your upkeep, exile the top card of your library. You may play it this turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Warped Space${4}{R}{R}$Enchantment -- Room$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Charred Foyer // Warped Space|Duskmourn: House of Horror|129|M|{3}{R}","{4}{R}{R}|Enchantment - Room|||Charred Foyer$At the beginning of your upkeep, exile the top card of your library. You may play it this turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Warped Space$Enchantment -- Room$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Clockwork Percussionist|Duskmourn: House of Horror|130|C|{R}|Artifact Creature - Monkey Toy|1|1|Haste$When this creature dies, exile the top card of your library. You may play it until the end of your next turn.| Cursed Recording|Duskmourn: House of Horror|131|R|{2}{R}{R}|Artifact|||Whenever you cast an instant or sorcery spell, put a time counter on this artifact. Then if there are seven or more time counters on it, remove those counters and it deals 20 damage to you.${T}: When you next cast an instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.| Diversion Specialist|Duskmourn: House of Horror|132|U|{3}{R}|Creature - Human Warrior|4|3|Menace${1}, Sacrifice another creature or enchantment: Exile the top card of your library. You may play it this turn.| @@ -54116,7 +54116,7 @@ Enduring Courage|Duskmourn: House of Horror|133|R|{2}{R}{R}|Enchantment Creature Fear of Being Hunted|Duskmourn: House of Horror|134|U|{1}{R}{R}|Enchantment Creature - Nightmare|4|2|Haste$This creature must be blocked if able.| Fear of Burning Alive|Duskmourn: House of Horror|135|U|{4}{R}{R}|Enchantment Creature - Nightmare|4|4|When this creature enters, it deals 4 damage to each opponent.$Delirium -- Whenever a source you control deals noncombat damage to an opponent, if there are four or more card types among cards in your graveyard, this creature deals that amount of damage to target creature that player controls.| Fear of Missing Out|Duskmourn: House of Horror|136|R|{1}{R}|Enchantment Creature - Nightmare|2|3|When this creature enters, discard a card, then draw a card.$Delirium -- Whenever this creature attacks for the first time each turn, if there are four or more card types among cards in your graveyard, untap target creature. After this phase, there is an additional combat phase.| -Glassworks // Shattered Yard|Duskmourn: House of Horror|137|C|{2}{R}|Enchantment - Room|||When you unlock this door, this Room deals 4 damage to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Shattered Yard${4}{R}$Enchantment -- Room$At the beginning of your end step, this Room deals 1 damage to each opponent.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Glassworks // Shattered Yard|Duskmourn: House of Horror|137|C|{2}{R}","{4}{R}|Enchantment - Room|||Glassworks$When you unlock this door, this Room deals 4 damage to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Shattered Yard$Enchantment -- Room$At the beginning of your end step, this Room deals 1 damage to each opponent.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Grab the Prize|Duskmourn: House of Horror|138|C|{1}{R}|Sorcery|||As an additional cost to cast this spell, discard a card.$Draw two cards. If the discarded card wasn't a land card, Grab the Prize deals 2 damage to each opponent.| Hand That Feeds|Duskmourn: House of Horror|139|C|{1}{R}|Creature - Mutant|2|2|Delirium -- Whenever this creature attacks while there are four or more card types among cards in your graveyard, it gets +2/+0 and gains menace until end of turn.| Impossible Inferno|Duskmourn: House of Horror|140|C|{4}{R}|Instant|||Impossible Inferno deals 6 damage to target creature.$Delirium -- If there are four or more card types among cards in your graveyard, exile the top card of your library. You may play it until the end of your next turn.| @@ -54127,7 +54127,7 @@ Leyline of Resonance|Duskmourn: House of Horror|143|R|{2}{R}{R}|Enchantment|||If Most Valuable Slayer|Duskmourn: House of Horror|144|C|{3}{R}|Creature - Human Warrior|2|4|Whenever you attack, target attacking creature gets +1/+0 and gains first strike until end of turn.| Norin, Swift Survivalist|Duskmourn: House of Horror|145|U|{R}|Legendary Creature - Human Coward|2|1|Norin can't block.$Whenever a creature you control becomes blocked, you may exile it. You may play that card from exile this turn.| Overlord of the Boilerbilges|Duskmourn: House of Horror|146|M|{4}{R}{R}|Enchantment Creature - Avatar Horror|5|5|Impending 4--{2}{R}{R}$Whenever this permanent enters or attacks, it deals 4 damage to any target.| -Painter's Studio // Defaced Gallery|Duskmourn: House of Horror|147|U|{2}{R}|Enchantment - Room|||When you unlock this door, exile the top two cards of your library. You may play them until the end of your next turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Defaced Gallery${1}{R}$Enchantment -- Room$Whenever you attack, attacking creatures you control get +1/+0 until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Painter's Studio // Defaced Gallery|Duskmourn: House of Horror|147|U|{2}{R}","{1}{R}|Enchantment - Room|||Painter's Studio$When you unlock this door, exile the top two cards of your library. You may play them until the end of your next turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Defaced Gallery$Enchantment -- Room$Whenever you attack, attacking creatures you control get +1/+0 until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Piggy Bank|Duskmourn: House of Horror|148|U|{1}{R}|Artifact Creature - Boar Toy|3|2|When this creature dies, create a Treasure token.| Pyroclasm|Duskmourn: House of Horror|149|U|{1}{R}|Sorcery|||Pyroclasm deals 2 damage to each creature.| Ragged Playmate|Duskmourn: House of Horror|150|C|{1}{R}|Artifact Creature - Toy|2|2|{1}, {T}: Target creature with power 2 or less can't be blocked this turn.| @@ -54138,7 +54138,7 @@ Ripchain Razorkin|Duskmourn: House of Horror|154|C|{3}{R}|Creature - Human Berse The Rollercrusher Ride|Duskmourn: House of Horror|155|M|{X}{2}{R}|Legendary Enchantment|||Delirium -- If a source you control would deal noncombat damage to a permanent or player while there are four or more card types among cards in your graveyard, it deals double that damage instead.$When The Rollercrusher Ride enters, it deals X damage to each of up to X target creatures.| Scorching Dragonfire|Duskmourn: House of Horror|156|C|{1}{R}|Instant|||Scorching Dragonfire deals 3 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead.| Screaming Nemesis|Duskmourn: House of Horror|157|M|{2}{R}|Creature - Spirit|3|3|Haste$Whenever this creature is dealt damage, it deals that much damage to any other target. If a player is dealt damage this way, they can't gain life for the rest of the game.| -Ticket Booth // Tunnel of Hate|Duskmourn: House of Horror|158|C|{2}{R}|Enchantment - Room|||When you unlock this door, manifest dread.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Tunnel of Hate${4}{R}{R}$Enchantment -- Room$Whenever you attack, target attacking creature gains double strike until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Ticket Booth // Tunnel of Hate|Duskmourn: House of Horror|158|C|{2}{R}","{4}{R}{R}|Enchantment - Room|||Ticket Booth$When you unlock this door, manifest dread.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Tunnel of Hate$Enchantment -- Room$Whenever you attack, target attacking creature gains double strike until end of turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Trial of Agony|Duskmourn: House of Horror|159|U|{R}|Sorcery|||Choose two target creatures controlled by the same opponent. That player chooses one of those creatures. Trial of Agony deals 5 damage to that creature, and the other can't block this turn.| Turn Inside Out|Duskmourn: House of Horror|160|C|{R}|Instant|||Target creature gets +3/+0 until end of turn. When it dies this turn, manifest dread.| Untimely Malfunction|Duskmourn: House of Horror|161|U|{1}{R}|Instant|||Choose one --$* Destroy target artifact.$* Change the target of target spell or ability with a single target.$* One or two target creatures can't block this turn.| @@ -54161,7 +54161,7 @@ Fear of Exposure|Duskmourn: House of Horror|177|U|{2}{G}|Enchantment Creature - Flesh Burrower|Duskmourn: House of Horror|178|C|{1}{G}|Creature - Insect|2|2|Deathtouch$Whenever this creature attacks, another target creature you control gains deathtouch until end of turn.| Frantic Strength|Duskmourn: House of Horror|179|C|{2}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +2/+2 and has trample.| Grasping Longneck|Duskmourn: House of Horror|180|C|{2}{G}|Enchantment Creature - Horror|4|2|Reach$When this creature dies, you gain 2 life.| -Greenhouse // Rickety Gazebo|Duskmourn: House of Horror|181|U|{2}{G}|Enchantment - Room|||Lands you control have "{T}: Add one mana of any color."$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Rickety Gazebo${3}{G}$Enchantment -- Room$When you unlock this door, mill four cards, then return up to two permanent cards from among them to your hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Greenhouse // Rickety Gazebo|Duskmourn: House of Horror|181|U|{2}{G}","{3}{G}|Enchantment - Room|||Greenhouse$Lands you control have "{T}: Add one mana of any color."$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Rickety Gazebo$Enchantment -- Room$When you unlock this door, mill four cards, then return up to two permanent cards from among them to your hand.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Hauntwoods Shrieker|Duskmourn: House of Horror|182|M|{1}{G}{G}|Creature - Beast Mutant|3|3|Whenever this creature attacks, manifest dread.${1}{G}: Reveal target face-down permanent. If it's a creature card, you may turn it face up.| Hedge Shredder|Duskmourn: House of Horror|183|R|{2}{G}{G}|Artifact - Vehicle|5|5|Whenever this Vehicle attacks, you may mill two cards.$Whenever one or more land cards are put into your graveyard from your library, put them onto the battlefield tapped.$Crew 1| Horrid Vigor|Duskmourn: House of Horror|184|C|{1}{G}|Instant|||Target creature gains deathtouch and indestructible until end of turn.| @@ -54170,7 +54170,7 @@ Insidious Fungus|Duskmourn: House of Horror|186|U|{G}|Creature - Fungus|1|2|{2}, Kona, Rescue Beastie|Duskmourn: House of Horror|187|R|{3}{G}|Legendary Creature - Beast Survivor|4|3|Survival -- At the beginning of your second main phase, if Kona is tapped, you may put a permanent card from your hand onto the battlefield.| Leyline of Mutation|Duskmourn: House of Horror|188|R|{2}{G}{G}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$You may pay {W}{U}{B}{R}{G} rather than pay the mana cost for spells you cast.| Manifest Dread|Duskmourn: House of Horror|189|C|{1}{G}|Sorcery|||Manifest dread.| -Moldering Gym // Weight Room|Duskmourn: House of Horror|190|C|{2}{G}|Enchantment - Room|||When you unlock this door, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Weight Room${5}{G}$Enchantment -- Room$When you unlock this door, manifest dread, then put three +1/+1 counters on that creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Moldering Gym // Weight Room|Duskmourn: House of Horror|190|C|{2}{G}","{5}{G}|Enchantment - Room|||Moldering Gym$When you unlock this door, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Weight Room$Enchantment -- Room$When you unlock this door, manifest dread, then put three +1/+1 counters on that creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Monstrous Emergence|Duskmourn: House of Horror|191|C|{1}{G}|Sorcery|||As an additional cost to cast this spell, choose a creature you control or reveal a creature card from your hand.$Monstrous Emergence deals damage equal to the power of the creature you chose or the card you revealed to target creature.| Omnivorous Flytrap|Duskmourn: House of Horror|192|R|{2}{G}|Creature - Plant|2|4|Delirium -- Whenever this creature enters or attacks, if there are four or more card types among cards in your graveyard, distribute two +1/+1 counters among one or two target creatures. Then if there are six or more card types among cards in your graveyard, double the number of +1/+1 counters on those creatures.| Overgrown Zealot|Duskmourn: House of Horror|193|U|{1}{G}|Creature - Elf Druid|0|4|{T}: Add one mana of any color.${T}: Add two mana of any one color. Spend this mana only to turn permanents face up.| @@ -54185,7 +54185,7 @@ Twitching Doll|Duskmourn: House of Horror|201|R|{1}{G}|Artifact Creature - Spide Tyvar, the Pummeler|Duskmourn: House of Horror|202|M|{1}{G}{G}|Legendary Creature - Elf Warrior|3|3|Tap another untapped creature you control: Tyvar gains indestructible until end of turn. Tap it.${3}{G}{G}: Creatures you control get +X/+X until end of turn, where X is the greatest power among creatures you control.| Under the Skin|Duskmourn: House of Horror|203|U|{2}{G}|Sorcery|||Manifest dread.$You may return a permanent card from your graveyard to your hand.| Valgavoth's Onslaught|Duskmourn: House of Horror|204|R|{X}{X}{G}|Sorcery|||Manifest dread X times, then put X +1/+1 counters on each of those creatures.| -Walk-In Closet // Forgotten Cellar|Duskmourn: House of Horror|205|M|{2}{G}|Enchantment - Room|||You may play lands from your graveyard.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Forgotten Cellar${3}{G}{G}$Enchantment -- Room$When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Walk-In Closet // Forgotten Cellar|Duskmourn: House of Horror|205|M|{2}{G}","{3}{G}{G}|Enchantment - Room|||Walk-In Closet$You may play lands from your graveyard.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Forgotten Cellar$Enchantment -- Room$When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Wary Watchdog|Duskmourn: House of Horror|206|C|{1}{G}|Creature - Dog|3|1|When this creature enters or dies, surveil 1.| Wickerfolk Thresher|Duskmourn: House of Horror|207|U|{3}{G}|Artifact Creature - Scarecrow|5|4|Delirium -- Whenever this creature attacks, if there are four or more card types among cards in your graveyard, look at the top card of your library. If it's a land card, you may put it onto the battlefield. If you don't put the card onto the battlefield, put it into your hand.| Arabella, Abandoned Doll|Duskmourn: House of Horror|208|U|{R}{W}|Legendary Artifact Creature - Toy|1|3|Whenever Arabella attacks, it deals X damage to each opponent and you gain X life, where X is the number of creatures you control with power 2 or less.| @@ -54207,15 +54207,15 @@ Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Cr Niko, Light of Hope|Duskmourn: House of Horror|224|M|{2}{W}{U}|Legendary Creature - Human Wizard|3|4|When Niko enters, create two Shard tokens.${2}, {T}: Exile target nonlegendary creature you control. Shards you control become copies of it until the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step.| Oblivious Bookworm|Duskmourn: House of Horror|225|U|{G}{U}|Creature - Human Wizard|2|3|At the beginning of your end step, you may draw a card. If you do, discard a card unless a permanent entered the battlefield face down under your control this turn or you turned a permanent face up this turn.| Peer Past the Veil|Duskmourn: House of Horror|226|R|{2}{R}{G}|Instant|||Discard your hand. Then draw X cards, where X is the number of card types among cards in your graveyard.| -Restricted Office // Lecture Hall|Duskmourn: House of Horror|227|R|{2}{W}{W}|Enchantment - Room|||When you unlock this door, destroy all creatures with power 3 or greater.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lecture Hall${5}{U}{U}$Enchantment -- Room$Other permanents you control have hexproof.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Restricted Office // Lecture Hall|Duskmourn: House of Horror|227|R|{2}{W}{W}","{5}{U}{U}|Enchantment - Room|||Restricted Office$When you unlock this door, destroy all creatures with power 3 or greater.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lecture Hall$Enchantment -- Room$Other permanents you control have hexproof.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Rip, Spawn Hunter|Duskmourn: House of Horror|228|R|{2}{G}{W}|Legendary Creature - Human Survivor|4|4|Survival -- At the beginning of your second main phase, if Rip is tapped, reveal the top X cards of your library, where X is its power. Put any number of creature and/or Vehicle cards with different powers from among them into your hand. Put the rest on the bottom of your library in a random order.| Rite of the Moth|Duskmourn: House of Horror|229|U|{1}{W}{B}{B}|Sorcery|||Return target creature card from your graveyard to the battlefield with a finality counter on it.$Flashback {3}{W}{W}{B}| -Roaring Furnace // Steaming Sauna|Duskmourn: House of Horror|230|R|{1}{R}|Enchantment - Room|||When you unlock this door, this Room deals damage equal to the number of cards in your hand to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Steaming Sauna${3}{U}{U}$Enchantment -- Room$You have no maximum hand size.$At the beginning of your end step, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Roaring Furnace // Steaming Sauna|Duskmourn: House of Horror|230|R|{1}{R}","{3}{U}{U}|Enchantment - Room|||Roaring Furnace$When you unlock this door, this Room deals damage equal to the number of cards in your hand to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Steaming Sauna$Enchantment -- Room$You have no maximum hand size.$At the beginning of your end step, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Sawblade Skinripper|Duskmourn: House of Horror|231|U|{1}{B}{R}|Creature - Human Assassin|3|2|Menace${2}, Sacrifice another creature or enchantment: Put a +1/+1 counter on this creature.$At the beginning of your end step, if you sacrificed one or more permanents this turn, this creature deals that much damage to any target.| Shrewd Storyteller|Duskmourn: House of Horror|232|U|{1}{G}{W}|Creature - Human Survivor|3|3|Survival -- At the beginning of your second main phase, if this creature is tapped, put a +1/+1 counter on target creature.| Shroudstomper|Duskmourn: House of Horror|233|U|{3}{W}{W}{B}{B}|Creature - Elemental|5|5|Deathtouch$Whenever this creature enters or attacks, each opponent loses 2 life. You gain 2 life and draw a card.| Skullsnap Nuisance|Duskmourn: House of Horror|234|U|{U}{B}|Creature - Insect Skeleton|1|4|Flying$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, surveil 1.| -Smoky Lounge // Misty Salon|Duskmourn: House of Horror|235|U|{2}{R}|Enchantment - Room|||At the beginning of your first main phase, add {R}{R}. Spend this mana only to cast Room spells and unlock doors.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Misty Salon${3}{U}$Enchantment -- Room$When you unlock this door, create an X/X blue Spirit creature token with flying, where X is the number of unlocked doors among Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Smoky Lounge // Misty Salon|Duskmourn: House of Horror|235|U|{2}{R}","{3}{U}|Enchantment - Room|||Smoky Lounge$At the beginning of your first main phase, add {R}{R}. Spend this mana only to cast Room spells and unlock doors.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Misty Salon$Enchantment -- Room$When you unlock this door, create an X/X blue Spirit creature token with flying, where X is the number of unlocked doors among Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| The Swarmweaver|Duskmourn: House of Horror|236|R|{2}{B}{G}|Legendary Artifact Creature - Scarecrow|2|3|When The Swarmweaver enters, create two 1/1 black and green Insect creature tokens with flying.$Delirium -- As long as there are four or more card types among cards in your graveyard, Insects and Spiders you control get +1/+1 and have deathtouch.| Undead Sprinter|Duskmourn: House of Horror|237|R|{B}{R}|Creature - Zombie|2|2|Trample, haste$You may cast this card from your graveyard if a non-Zombie creature died this turn. If you do, this creature enters with a +1/+1 counter on it.| Victor, Valgavoth's Seneschal|Duskmourn: House of Horror|238|R|{1}{W}{B}|Legendary Creature - Human Warlock|3|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, surveil 2 if this is the first time this ability has resolved this turn. If it's the second time, each opponent discards a card. If it's the third time, put a creature card from a graveyard onto the battlefield under your control.| @@ -54267,7 +54267,7 @@ Mountain|Duskmourn: House of Horror|283|C||Basic Land - Mountain|||({T}: Add {R} Mountain|Duskmourn: House of Horror|284|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Duskmourn: House of Horror|285|C||Basic Land - Forest|||({T}: Add {G}.)| Forest|Duskmourn: House of Horror|286|C||Basic Land - Forest|||({T}: Add {G}.)| -Grand Entryway // Elegant Rotunda|Duskmourn: House of Horror|287|C|{1}{W}|Enchantment - Room|||When you unlock this door, create a 1/1 white Glimmer enchantment creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Elegant Rotunda${2}{W}$Enchantment -- Room$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Grand Entryway // Elegant Rotunda|Duskmourn: House of Horror|287|C|{1}{W}","{2}{W}|Enchantment - Room|||Grand Entryway$When you unlock this door, create a 1/1 white Glimmer enchantment creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Elegant Rotunda$Enchantment -- Room$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Optimistic Scavenger|Duskmourn: House of Horror|288|U|{W}|Creature - Human Scout|1|1|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, put a +1/+1 counter on target creature.| Reluctant Role Model|Duskmourn: House of Horror|289|R|{1}{W}|Creature - Human Survivor|2|2|Survival -- At the beginning of your second main phase, if this creature is tapped, put a flying, lifelink, or +1/+1 counter on it.$Whenever this creature or another creature you control dies, if it had counters on it, put those counters on up to one target creature.| Entity Tracker|Duskmourn: House of Horror|290|R|{2}{U}|Creature - Human Scout|2|3|Flash$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, draw a card.| @@ -54314,16 +54314,16 @@ Floodfarm Verge|Duskmourn: House of Horror|330|R||Land|||{T}: Add {W}.${T}: Add Gloomlake Verge|Duskmourn: House of Horror|331|R||Land|||{T}: Add {U}.${T}: Add {B}. Activate only if you control an Island or a Swamp.| Hushwood Verge|Duskmourn: House of Horror|332|R||Land|||{T}: Add {G}.${T}: Add {W}. Activate only if you control a Forest or a Plains.| Thornspire Verge|Duskmourn: House of Horror|333|R||Land|||{T}: Add {R}.${T}: Add {G}. Activate only if you control a Mountain or a Forest.| -Dazzling Theater // Prop Room|Duskmourn: House of Horror|334|R|{3}{W}|Enchantment - Room|||Creature spells you cast have convoke.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Prop Room${2}{W}$Enchantment -- Room$Untap each creature you control during each other player's untap step.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|335|M|{1}{W}|Enchantment - Room|||Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Porcelain Gallery${4}{W}{W}$Enchantment -- Room$Creatures you control have base power and toughness each equal to the number of creatures you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Central Elevator // Promising Stairs|Duskmourn: House of Horror|336|R|{3}{U}|Enchantment - Room|||When you unlock this door, search your library for a Room card that doesn't have the same name as a Room you control, reveal it, put it into your hand, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Promising Stairs${2}{U}$Enchantment -- Room$At the beginning of your upkeep, surveil 1. You win the game if there are eight or more different names among unlocked doors of Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Mirror Room // Fractured Realm|Duskmourn: House of Horror|337|M|{2}{U}|Enchantment - Room|||When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Fractured Realm${5}{U}{U}$Enchantment -- Room$If a triggered ability of a permanent you control triggers, that ability triggers an additional time.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Funeral Room // Awakening Hall|Duskmourn: House of Horror|338|M|{2}{B}|Enchantment - Room|||Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Awakening Hall${6}{B}{B}$Enchantment -- Room$When you unlock this door, return all creature cards from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Unholy Annex // Ritual Chamber|Duskmourn: House of Horror|339|R|{2}{B}|Enchantment - Room|||At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Ritual Chamber${3}{B}{B}$Enchantment -- Room$When you unlock this door, create a 6/6 black Demon creature token with flying.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Charred Foyer // Warped Space|Duskmourn: House of Horror|340|M|{3}{R}|Enchantment - Room|||At the beginning of your upkeep, exile the top card of your library. You may play it this turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Warped Space${4}{R}{R}$Enchantment -- Room$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Walk-In Closet // Forgotten Cellar|Duskmourn: House of Horror|341|M|{2}{G}|Enchantment - Room|||You may play lands from your graveyard.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Forgotten Cellar${3}{G}{G}$Enchantment -- Room$When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Restricted Office // Lecture Hall|Duskmourn: House of Horror|342|R|{2}{W}{W}|Enchantment - Room|||When you unlock this door, destroy all creatures with power 3 or greater.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lecture Hall${5}{U}{U}$Enchantment -- Room$Other permanents you control have hexproof.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| -Roaring Furnace // Steaming Sauna|Duskmourn: House of Horror|343|R|{1}{R}|Enchantment - Room|||When you unlock this door, this Room deals damage equal to the number of cards in your hand to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Steaming Sauna${3}{U}{U}$Enchantment -- Room$You have no maximum hand size.$At the beginning of your end step, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Dazzling Theater // Prop Room|Duskmourn: House of Horror|334|R|{3}{W}","{2}{W}|Enchantment - Room|||Dazzling Theater$Creature spells you cast have convoke.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Prop Room$Enchantment -- Room$Untap each creature you control during each other player's untap step.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|335|M|{1}{W}","{4}{W}{W}|Enchantment - Room|||Dollmaker's Shop$Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Porcelain Gallery$Enchantment -- Room$Creatures you control have base power and toughness each equal to the number of creatures you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Central Elevator // Promising Stairs|Duskmourn: House of Horror|336|R|{3}{U}","{2}{U}|Enchantment - Room|||Central Elevator$When you unlock this door, search your library for a Room card that doesn't have the same name as a Room you control, reveal it, put it into your hand, then shuffle.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Promising Stairs$Enchantment -- Room$At the beginning of your upkeep, surveil 1. You win the game if there are eight or more different names among unlocked doors of Rooms you control.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Mirror Room // Fractured Realm|Duskmourn: House of Horror|337|M|{2}{U}","{5}{U}{U}|Enchantment - Room|||Mirror Room$When you unlock this door, create a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Fractured Realm$Enchantment -- Room$If a triggered ability of a permanent you control triggers, that ability triggers an additional time.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Funeral Room // Awakening Hall|Duskmourn: House of Horror|338|M|{2}{B}","{6}{B}{B}|Enchantment - Room|||Funeral Room$Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Awakening Hall$Enchantment -- Room$When you unlock this door, return all creature cards from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Unholy Annex // Ritual Chamber|Duskmourn: House of Horror|339|R|{2}{B}","{3}{B}{B}|Enchantment - Room|||Unholy Annex$At the beginning of your end step, draw a card. If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Ritual Chamber$Enchantment -- Room$When you unlock this door, create a 6/6 black Demon creature token with flying.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Charred Foyer // Warped Space|Duskmourn: House of Horror|340|M|{3}{R}","{4}{R}{R}|Enchantment - Room|||Charred Foyer$At the beginning of your upkeep, exile the top card of your library. You may play it this turn.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Warped Space$Enchantment -- Room$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Walk-In Closet // Forgotten Cellar|Duskmourn: House of Horror|341|M|{2}{G}","{3}{G}{G}|Enchantment - Room|||Walk-In Closet$You may play lands from your graveyard.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Forgotten Cellar$Enchantment -- Room$When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Restricted Office // Lecture Hall|Duskmourn: House of Horror|342|R|{2}{W}{W}","{5}{U}{U}|Enchantment - Room|||Restricted Office$When you unlock this door, destroy all creatures with power 3 or greater.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Lecture Hall$Enchantment -- Room$Other permanents you control have hexproof.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Roaring Furnace // Steaming Sauna|Duskmourn: House of Horror|343|R|{1}{R}","{3}{U}{U}|Enchantment - Room|||Roaring Furnace$When you unlock this door, this Room deals damage equal to the number of cards in your hand to target creature an opponent controls.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Steaming Sauna$Enchantment -- Room$You have no maximum hand size.$At the beginning of your end step, draw a card.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Abhorrent Oculus|Duskmourn: House of Horror|344|M|{2}{U}|Creature - Eye|5|5|As an additional cost to cast this spell, exile six cards from your graveyard.$Flying$At the beginning of each opponent's upkeep, manifest dread.| Silent Hallcreeper|Duskmourn: House of Horror|345|R|{1}{U}|Enchantment Creature - Horror|1|1|This creature can't be blocked.$Whenever this creature deals combat damage to a player, choose one that hasn't been chosen --$* Put two +1/+1 counters on this creature.$* Draw a card.$* This creature becomes a copy of another target creature you control.| Doomsday Excruciator|Duskmourn: House of Horror|346|R|{B}{B}{B}{B}{B}{B}|Creature - Demon|6|6|Flying$When this creature enters, if it was cast, each player exiles all but the bottom six cards of their library face down.$At the beginning of your upkeep, draw a card.| @@ -55243,44 +55243,71 @@ Aminatou, Veil Piercer|Duskmourn: House of Horror Commander|1|M|{1}{W}{U}{B}|Leg Kianne, Corrupted Memory|Duskmourn: House of Horror Commander|2|M|{2}{G}{U}|Legendary Creature - Illusion|2|2|As long as Kianne's power is even, you may cast noncreature spells as though they had flash.$As long as Kianne's power is odd, you may cast creature spells as though they had flash.$Whenever you draw a card, put a +1/+1 counter on Kianne.| The Lord of Pain|Duskmourn: House of Horror Commander|3|M|{3}{B}{R}|Legendary Creature - Human Assassin|5|5|Menace$Your opponents can't gain life.$Whenever a player casts their first spell each turn, choose another target player. The Lord of Pain deals damage equal to that spell's mana value to the chosen player.| The Master of Keys|Duskmourn: House of Horror Commander|4|M|{X}{W}{U}{B}|Legendary Enchantment Creature - Horror|3|3|Flying$When The Master of Keys enters, put X +1/+1 counters on it and mill twice X cards.$Each enchantment card in your graveyard has escape. The escape cost is equal to the card's mana cost plus exile three other cards from your graveyard.| -Rendmaw, Creaking Nest|Duskmourn: House of Horror Commander|5|M|{3}{B}{G}|Legendary Artifact Creature - Scarecrow|5|5|Menace, reach$When Rendmaw, Creaking Nest enters and whenever you play a card with two or more card types, each player creates a tapped 2/2 black Bird creature token with flying. The tokens are goaded for the rest of the game.| -Valgavoth, Harrower of Souls|Duskmourn: House of Horror Commander|6|M|{2}{B}{R}|Legendary Creature - Elder Demon|4|4|Flying$Ward--Pay 2 life.$Whenever an opponent loses life for the first time during each of their turns, put a +1/+1 counter on Valgavoth, Harrower of Souls and draw a card.| +Rendmaw, Creaking Nest|Duskmourn: House of Horror Commander|5|M|{3}{B}{G}|Legendary Artifact Creature - Scarecrow|5|5|Menace, reach$When Rendmaw enters and whenever you play a card with two or more card types, each player creates a tapped 2/2 black Bird creature token with flying. The tokens are goaded for the rest of the game.| +Valgavoth, Harrower of Souls|Duskmourn: House of Horror Commander|6|M|{2}{B}{R}|Legendary Creature - Elder Demon|4|4|Flying$Ward--Pay 2 life.$Whenever an opponent loses life for the first time during each of their turns, put a +1/+1 counter on Valgavoth and draw a card.| Winter, Cynical Opportunist|Duskmourn: House of Horror Commander|7|M|{2}{B}{G}|Legendary Creature - Human Warlock|2|5|Deathtouch$Whenever Winter attacks, mill three cards.$Delirium -- At the beginning of your end step, you may exile any number of cards from your graveyard with four or more card types among them. If you do, put a permanent card from among them onto the battlefield with a finality counter on it.| Zimone, Mystery Unraveler|Duskmourn: House of Horror Commander|8|M|{2}{G}{U}|Legendary Creature - Human Wizard|3|3|Landfall -- Whenever a land you control enters, manifest dread if this is the first time this ability has resolved this turn. Otherwise, you may turn a permanent you control face up.| Redress Fate|Duskmourn: House of Horror Commander|9|R|{6}{W}{W}|Sorcery|||Return all artifact and enchantment cards from your graveyard to the battlefield.$Miracle {3}{W}| -Secret Arcade // Dusty Parlor|Duskmourn: House of Horror Commander|10|R|{4}{W}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Nonland permanents you control and permanent spells you control are enchantments in addition to their other types.$Dusty Parlor${2}{W}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever you cast an enchantment spell, put a number of +1/+1 counters equal to that spell's mana value on up to one target creature.| +Secret Arcade // Dusty Parlor|Duskmourn: House of Horror Commander|10|R|{4}{W}","{2}{W}|Enchantment - Room|||Secret Arcade$Nonland permanents you control and permanent spells you control are enchantments in addition to their other types.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Dusty Parlor$Enchantment -- Room$Whenever you cast an enchantment spell, put a number of +1/+1 counters equal to that spell's mana value on up to one target creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Soaring Lightbringer|Duskmourn: House of Horror Commander|11|R|{4}{W}|Enchantment Creature - Bird Glimmer|4|5|Flying$Other enchantment creatures you control have flying.$Whenever you attack a player, create a 1/1 white Glimmer enchantment creature token that's tapped and attacking that player.| -Fear of Sleep Paralysis|Duskmourn: House of Horror Commander|12|R|{5}{U}|Enchantment Creature - Nightmare|6|6|Flying$Eerie -- Whenever Fear of Sleep Paralysis or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.$Stun counters can't be removed from permanents your opponents control.| -Glitch Interpreter|Duskmourn: House of Horror Commander|13|R|{2}{U}|Creature - Human Wizard|2|3|When Glitch Interpreter enters, if you control no face-down permanents, return Glitch Interpreter to its owner's hand and manifest dread.$Whenever one or more colorless creatures you control deal combat damage to a player, draw a card.| -They Came from the Pipes|Duskmourn: House of Horror Commander|14|R|{4}{U}|Enchantment|||When They Came from the Pipes enters, manifest dread twice.$Whenever a face-down creature you control enters, draw a card.| +Fear of Sleep Paralysis|Duskmourn: House of Horror Commander|12|R|{5}{U}|Enchantment Creature - Nightmare|6|6|Flying$Eerie -- Whenever this creature or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.$Stun counters can't be removed from permanents your opponents control.| +Glitch Interpreter|Duskmourn: House of Horror Commander|13|R|{2}{U}|Creature - Human Wizard|2|3|When this creature enters, if you control no face-down permanents, return this creature to its owner's hand and manifest dread.$Whenever one or more colorless creatures you control deal combat damage to a player, draw a card.| +They Came from the Pipes|Duskmourn: House of Horror Commander|14|R|{4}{U}|Enchantment|||When this enchantment enters, manifest dread twice.$Whenever a face-down creature you control enters, draw a card.| Zimone's Hypothesis|Duskmourn: House of Horror Commander|15|R|{3}{U}{U}|Instant|||You may put a +1/+1 counter on a creature. Then choose odd or even. Return each creature with power of the chosen quality to its owner's hand.| Ancient Cellarspawn|Duskmourn: House of Horror Commander|16|R|{1}{B}{B}|Enchantment Creature - Horror|3|3|Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.$Whenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.| -Cramped Vents // Access Maze|Duskmourn: House of Horror Commander|17|R|{3}{B}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, this Room deals 6 damage to target creature an opponent controls. You gain life equal to the excess damage dealt this way.$Access Maze${5}{B}{B}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Once during each of your turns, you may cast a spell from your hand by paying life equal to its mana value rather than paying its mana cost.| +Cramped Vents // Access Maze|Duskmourn: House of Horror Commander|17|R|{3}{B}","{5}{B}{B}|Enchantment - Room|||Cramped Vents$When you unlock this door, this Room deals 6 damage to target creature an opponent controls. You gain life equal to the excess damage dealt this way.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Access Maze$Enchantment -- Room$Once during each of your turns, you may cast a spell from your hand by paying life equal to its mana value rather than paying its mana cost.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Deluge of Doom|Duskmourn: House of Horror Commander|18|R|{2}{B}|Sorcery|||All creatures get -X/-X until end of turn, where X is the number of card types among cards in your graveyard.| -Demonic Covenant|Duskmourn: House of Horror Commander|19|R|{4}{B}{B}|Kindred Enchantment - Demon|||Whenever one or more Demons you control attack a player, you draw a card and lose 1 life.$At the beginning of your end step, create a 5/5 black Demon creature token with flying, then mill two cards. If two cards that share all their card types were milled this way, sacrifice Demonic Covenant.| +Demonic Covenant|Duskmourn: House of Horror Commander|19|R|{4}{B}{B}|Kindred Enchantment - Demon|||Whenever one or more Demons you control attack a player, you draw a card and lose 1 life.$At the beginning of your end step, create a 5/5 black Demon creature token with flying, then mill two cards. If two cards that share all their card types were milled this way, sacrifice this enchantment.| Into the Pit|Duskmourn: House of Horror Commander|20|R|{2}{B}|Enchantment|||You may look at the top card of your library any time.$You may cast spells from the top of your library by sacrificing a nonland permanent in addition to paying their other costs.| -Metamorphosis Fanatic|Duskmourn: House of Horror Commander|21|R|{4}{B}{B}|Creature - Human Cleric|4|4|Lifelink$When Metamorphosis Fanatic enters, return up to one target creature card from your graveyard to the battlefield with a lifelink counter on it.$Miracle {1}{B}| +Metamorphosis Fanatic|Duskmourn: House of Horror Commander|21|R|{4}{B}{B}|Creature - Human Cleric|4|4|Lifelink$When this creature enters, return up to one target creature card from your graveyard to the battlefield with a lifelink counter on it.$Miracle {1}{B}| Persistent Constrictor|Duskmourn: House of Horror Commander|22|R|{4}{B}|Creature - Zombie Snake|5|3|At the beginning of each opponent's upkeep, they lose 1 life and you put a -1/-1 counter on up to one target creature they control.$Persist| -Polluted Cistern // Dim Oubliette|Duskmourn: House of Horror Commander|23|R|{1}{B}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever one or more cards are put into your graveyard from your library, each opponent loses 1 life for each card type among those cards.$Dim Oubliette${4}{B}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, mill three cards, then return a creature card from your graveyard to the battlefield.| +Polluted Cistern // Dim Oubliette|Duskmourn: House of Horror Commander|23|R|{1}{B}","{4}{B}|Enchantment - Room|||Polluted Cistern$Whenever one or more cards are put into your graveyard from your library, each opponent loses 1 life for each card type among those cards.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Dim Oubliette$Enchantment -- Room$When you unlock this door, mill three cards, then return a creature card from your graveyard to the battlefield.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Sadistic Shell Game|Duskmourn: House of Horror Commander|24|R|{4}{B}|Sorcery|||Starting with the next opponent in turn order, each player chooses a creature you don't control. Destroy the chosen creatures.| Suspended Sentence|Duskmourn: House of Horror Commander|25|R|{3}{B}|Instant|||Destroy target creature an opponent controls. That player loses 3 life. Exile Suspended Sentence with three time counters on it.$Suspend 3--{1}{B}| -Barbflare Gremlin|Duskmourn: House of Horror Commander|26|R|{3}{R}|Creature - Gremlin|3|2|First strike, haste$Whenever a player taps a land for mana, if Barbflare Gremlin is tapped, that player adds one mana of any type that land produced. Then that land deals 1 damage to that player.| -Gleeful Arsonist|Duskmourn: House of Horror Commander|27|R|{2}{R}|Creature - Human Wizard|1|2|Whenever an opponent casts a noncreature spell, Gleeful Arsonist deals damage equal to its power to that player.$Undying| -Spiked Corridor // Torture Pit|Duskmourn: House of Horror Commander|28|R|{3}{R}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, create three 1/1 red Devil creature tokens with "When this creature dies, it deals 1 damage to any target."$Torture Pit${3}{R}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$If a source you control would deal noncombat damage to an opponent, it deals that much damage plus 2 instead.| -Star Athlete|Duskmourn: House of Horror Commander|29|R|{1}{R}{R}|Creature - Human Warrior|3|2|Menace$Whenever Star Athlete attacks, choose up to one target nonland permanent. Its controller may sacrifice it. If they don't, Star Athlete deals 5 damage to that player.$Blitz {3}{R}| -Curator Beastie|Duskmourn: House of Horror Commander|30|R|{4}{G}{G}|Creature - Beast|6|6|Reach$Colorless creatures you control enter with two additional +1/+1 counters on them.$Whenever Curator Beastie enters or attacks, manifest dread.| -Demolisher Spawn|Duskmourn: House of Horror Commander|31|R|{5}{G}{G}|Enchantment Creature - Horror|7|7|Trample, haste$Delirium -- Whenever Demolisher Spawn attacks, if there are four or more card types among cards in your graveyard, other attacking creatures get +4/+4 until end of turn.| +Barbflare Gremlin|Duskmourn: House of Horror Commander|26|R|{3}{R}|Creature - Gremlin|3|2|First strike, haste$Whenever a player taps a land for mana, if this creature is tapped, that player adds one mana of any type that land produced. Then that land deals 1 damage to that player.| +Gleeful Arsonist|Duskmourn: House of Horror Commander|27|R|{2}{R}|Creature - Human Wizard|1|2|Whenever an opponent casts a noncreature spell, this creature deals damage equal to its power to that player.$Undying| +Spiked Corridor // Torture Pit|Duskmourn: House of Horror Commander|28|R|{3}{R}","{3}{R}|Enchantment - Room|||Spiked Corridor$When you unlock this door, create three 1/1 red Devil creature tokens with "When this token dies, it deals 1 damage to any target."$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Torture Pit$Enchantment -- Room$If a source you control would deal noncombat damage to an opponent, it deals that much damage plus 2 instead.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| +Star Athlete|Duskmourn: House of Horror Commander|29|R|{1}{R}{R}|Creature - Human Warrior|3|2|Menace$Whenever this creature attacks, choose up to one target nonland permanent. Its controller may sacrifice it. If they don't, this creature deals 5 damage to that player.$Blitz {3}{R}| +Curator Beastie|Duskmourn: House of Horror Commander|30|R|{4}{G}{G}|Creature - Beast|6|6|Reach$Colorless creatures you control enter with two additional +1/+1 counters on them.$Whenever this creature enters or attacks, manifest dread.| +Demolisher Spawn|Duskmourn: House of Horror Commander|31|R|{5}{G}{G}|Enchantment Creature - Horror|7|7|Trample, haste$Delirium -- Whenever this creature attacks, if there are four or more card types among cards in your graveyard, other attacking creatures get +4/+4 until end of turn.| Disorienting Choice|Duskmourn: House of Horror Commander|32|R|{3}{G}|Sorcery|||For each opponent, choose up to one target artifact or enchantment that player controls. For each permanent chosen this way, its controller may exile it. Then if one or more of the chosen permanents are still on the battlefield, you search your library for up to that many land cards, put them onto the battlefield tapped, then shuffle.| -Experimental Lab // Staff Room|Duskmourn: House of Horror Commander|33|R|{3}{G}|Enchantment - Room|||(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$When you unlock this door, manifest dread, then put two +1/+1 counters and a trample counter on that creature.$Staff Room${2}{G}$Enchantment -- Room$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Whenever a creature you control deals combat damage to a player, turn that creature face up or put a +1/+1 counter on it.| +Experimental Lab // Staff Room|Duskmourn: House of Horror Commander|33|R|{3}{G}","{2}{G}|Enchantment - Room|||Experimental Lab$When you unlock this door, manifest dread, then put two +1/+1 counters and a trample counter on that creature.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)$Staff Room$Enchantment -- Room$Whenever a creature you control deals combat damage to a player, turn that creature face up or put a +1/+1 counter on it.$(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)| Formless Genesis|Duskmourn: House of Horror Commander|34|R|{2}{G}|Kindred Sorcery - Shapeshifter|||Changeling$Create an X/X colorless Shapeshifter creature token with changeling and deathtouch, where X is the number of land cards in your graveyard.$Retrace| Shriekwood Devourer|Duskmourn: House of Horror Commander|35|R|{5}{G}{G}|Creature - Treefolk|7|5|Trample$Whenever you attack with one or more creatures, untap up to X lands, where X is the greatest power among those creatures.| -Ursine Monstrosity|Duskmourn: House of Horror Commander|36|R|{2}{G}|Creature - Bear Mutant|3|3|Trample$At the beginning of combat on your turn, mill a card and choose an opponent at random. Ursine Monstrosity attacks that player this combat if able. Until end of turn, Ursine Monstrosity gains indestructible and gets +1/+1 for each card type among cards in your graveyard.| +Ursine Monstrosity|Duskmourn: House of Horror Commander|36|R|{2}{G}|Creature - Bear Mutant|3|3|Trample$At the beginning of combat on your turn, mill a card and choose an opponent at random. This creature attacks that player this combat if able. Until end of turn, this creature gains indestructible and gets +1/+1 for each card type among cards in your graveyard.| Convert to Slime|Duskmourn: House of Horror Commander|37|R|{3}{B}{G}|Sorcery|||Destroy up to one target artifact, up to one target creature, and up to one target enchantment.$Delirium -- Then if there are four or more card types among cards in your graveyard, create an X/X green Ooze creature token, where X is the total mana value of permanents destroyed this way.| -Phenomenon Investigators|Duskmourn: House of Horror Commander|38|R|{2}{U}{B}|Creature - Human Detective|3|4|As Phenomenon Investigators enters, choose Believe or Doubt.$* Believe -- Whenever a nontoken creature you control dies, create a 2/2 black Horror enchantment creature token.$* Doubt -- At the beginning of your end step, you may return a nonland permanent you own to your hand. If you do, draw a card.| -Giggling Skitterspike|Duskmourn: House of Horror Commander|39|R|{4}|Artifact Creature - Toy|1|1|Indestructible$Whenever Giggling Skitterspike attacks, blocks, or becomes the target of a spell, it deals damage equal to its power to each opponent.${5}: Monstrosity 5.| -Seance Board|Duskmourn: House of Horror Commander|40|R|{2}|Artifact|||Morbid -- At the beginning of each end step, if a creature died this turn, put a soul counter on Seance Board.${T}: Add X mana of any one color, where X is the number of soul counters on Seance Board. Spend this mana only to cast instant, sorcery, Demon, and Spirit spells.| +Phenomenon Investigators|Duskmourn: House of Horror Commander|38|R|{2}{U}{B}|Creature - Human Detective|3|4|As this creature enters, choose Believe or Doubt.$* Believe -- Whenever a nontoken creature you control dies, create a 2/2 black Horror enchantment creature token.$* Doubt -- At the beginning of your end step, you may return a nonland permanent you own to your hand. If you do, draw a card.| +Giggling Skitterspike|Duskmourn: House of Horror Commander|39|R|{4}|Artifact Creature - Toy|1|1|Indestructible$Whenever this creature attacks, blocks, or becomes the target of a spell, it deals damage equal to its power to each opponent.${5}: Monstrosity 5.| +Seance Board|Duskmourn: House of Horror Commander|40|R|{2}|Artifact|||Morbid -- At the beginning of each end step, if a creature died this turn, put a soul counter on this artifact.${T}: Add X mana of any one color, where X is the number of soul counters on this artifact. Spend this mana only to cast instant, sorcery, Demon, and Spirit spells.| +Redress Fate|Duskmourn: House of Horror Commander|41|R|{6}{W}{W}|Sorcery|||Return all artifact and enchantment cards from your graveyard to the battlefield.$Miracle {3}{W}| +Soaring Lightbringer|Duskmourn: House of Horror Commander|42|R|{4}{W}|Enchantment Creature - Bird Glimmer|4|5|Flying$Other enchantment creatures you control have flying.$Whenever you attack a player, create a 1/1 white Glimmer enchantment creature token that's tapped and attacking that player.| +Fear of Sleep Paralysis|Duskmourn: House of Horror Commander|43|R|{5}{U}|Enchantment Creature - Nightmare|6|6|Flying$Eerie -- Whenever this creature or another enchantment you control enters and whenever you fully unlock a Room, tap up to one target creature and put a stun counter on it.$Stun counters can't be removed from permanents your opponents control.| +Glitch Interpreter|Duskmourn: House of Horror Commander|44|R|{2}{U}|Creature - Human Wizard|2|3|When this creature enters, if you control no face-down permanents, return this creature to its owner's hand and manifest dread.$Whenever one or more colorless creatures you control deal combat damage to a player, draw a card.| +They Came from the Pipes|Duskmourn: House of Horror Commander|45|R|{4}{U}|Enchantment|||When this enchantment enters, manifest dread twice.$Whenever a face-down creature you control enters, draw a card.| +Zimone's Hypothesis|Duskmourn: House of Horror Commander|46|R|{3}{U}{U}|Instant|||You may put a +1/+1 counter on a creature. Then choose odd or even. Return each creature with power of the chosen quality to its owner's hand.| +Ancient Cellarspawn|Duskmourn: House of Horror Commander|47|R|{1}{B}{B}|Enchantment Creature - Horror|3|3|Each spell you cast that's a Demon, Horror, or Nightmare costs {1} less to cast.$Whenever you cast a spell, if the amount of mana spent to cast it was less than its mana value, target opponent loses life equal to the difference.| +Deluge of Doom|Duskmourn: House of Horror Commander|48|R|{2}{B}|Sorcery|||All creatures get -X/-X until end of turn, where X is the number of card types among cards in your graveyard.| +Demonic Covenant|Duskmourn: House of Horror Commander|49|R|{4}{B}{B}|Kindred Enchantment - Demon|||Whenever one or more Demons you control attack a player, you draw a card and lose 1 life.$At the beginning of your end step, create a 5/5 black Demon creature token with flying, then mill two cards. If two cards that share all their card types were milled this way, sacrifice this enchantment.| +Into the Pit|Duskmourn: House of Horror Commander|50|R|{2}{B}|Enchantment|||You may look at the top card of your library any time.$You may cast spells from the top of your library by sacrificing a nonland permanent in addition to paying their other costs.| +Metamorphosis Fanatic|Duskmourn: House of Horror Commander|51|R|{4}{B}{B}|Creature - Human Cleric|4|4|Lifelink$When this creature enters, return up to one target creature card from your graveyard to the battlefield with a lifelink counter on it.$Miracle {1}{B}| +Persistent Constrictor|Duskmourn: House of Horror Commander|52|R|{4}{B}|Creature - Zombie Snake|5|3|At the beginning of each opponent's upkeep, they lose 1 life and you put a -1/-1 counter on up to one target creature they control.$Persist| +Sadistic Shell Game|Duskmourn: House of Horror Commander|53|R|{4}{B}|Sorcery|||Starting with the next opponent in turn order, each player chooses a creature you don't control. Destroy the chosen creatures.| +Suspended Sentence|Duskmourn: House of Horror Commander|54|R|{3}{B}|Instant|||Destroy target creature an opponent controls. That player loses 3 life. Exile Suspended Sentence with three time counters on it.$Suspend 3--{1}{B}| +Barbflare Gremlin|Duskmourn: House of Horror Commander|55|R|{3}{R}|Creature - Gremlin|3|2|First strike, haste$Whenever a player taps a land for mana, if this creature is tapped, that player adds one mana of any type that land produced. Then that land deals 1 damage to that player.| +Gleeful Arsonist|Duskmourn: House of Horror Commander|56|R|{2}{R}|Creature - Human Wizard|1|2|Whenever an opponent casts a noncreature spell, this creature deals damage equal to its power to that player.$Undying| +Star Athlete|Duskmourn: House of Horror Commander|57|R|{1}{R}{R}|Creature - Human Warrior|3|2|Menace$Whenever this creature attacks, choose up to one target nonland permanent. Its controller may sacrifice it. If they don't, this creature deals 5 damage to that player.$Blitz {3}{R}| +Curator Beastie|Duskmourn: House of Horror Commander|58|R|{4}{G}{G}|Creature - Beast|6|6|Reach$Colorless creatures you control enter with two additional +1/+1 counters on them.$Whenever this creature enters or attacks, manifest dread.| +Demolisher Spawn|Duskmourn: House of Horror Commander|59|R|{5}{G}{G}|Enchantment Creature - Horror|7|7|Trample, haste$Delirium -- Whenever this creature attacks, if there are four or more card types among cards in your graveyard, other attacking creatures get +4/+4 until end of turn.| +Disorienting Choice|Duskmourn: House of Horror Commander|60|R|{3}{G}|Sorcery|||For each opponent, choose up to one target artifact or enchantment that player controls. For each permanent chosen this way, its controller may exile it. Then if one or more of the chosen permanents are still on the battlefield, you search your library for up to that many land cards, put them onto the battlefield tapped, then shuffle.| +Formless Genesis|Duskmourn: House of Horror Commander|61|R|{2}{G}|Kindred Sorcery - Shapeshifter|||Changeling$Create an X/X colorless Shapeshifter creature token with changeling and deathtouch, where X is the number of land cards in your graveyard.$Retrace| +Shriekwood Devourer|Duskmourn: House of Horror Commander|62|R|{5}{G}{G}|Creature - Treefolk|7|5|Trample$Whenever you attack with one or more creatures, untap up to X lands, where X is the greatest power among those creatures.| +Ursine Monstrosity|Duskmourn: House of Horror Commander|63|R|{2}{G}|Creature - Bear Mutant|3|3|Trample$At the beginning of combat on your turn, mill a card and choose an opponent at random. This creature attacks that player this combat if able. Until end of turn, this creature gains indestructible and gets +1/+1 for each card type among cards in your graveyard.| +Convert to Slime|Duskmourn: House of Horror Commander|64|R|{3}{B}{G}|Sorcery|||Destroy up to one target artifact, up to one target creature, and up to one target enchantment.$Delirium -- Then if there are four or more card types among cards in your graveyard, create an X/X green Ooze creature token, where X is the total mana value of permanents destroyed this way.| +Phenomenon Investigators|Duskmourn: House of Horror Commander|65|R|{2}{U}{B}|Creature - Human Detective|3|4|As this creature enters, choose Believe or Doubt.$* Believe -- Whenever a nontoken creature you control dies, create a 2/2 black Horror enchantment creature token.$* Doubt -- At the beginning of your end step, you may return a nonland permanent you own to your hand. If you do, draw a card.| +Giggling Skitterspike|Duskmourn: House of Horror Commander|66|R|{4}|Artifact Creature - Toy|1|1|Indestructible$Whenever this creature attacks, blocks, or becomes the target of a spell, it deals damage equal to its power to each opponent.${5}: Monstrosity 5.| +Seance Board|Duskmourn: House of Horror Commander|67|R|{2}|Artifact|||Morbid -- At the beginning of each end step, if a creature died this turn, put a soul counter on this artifact.${T}: Add X mana of any one color, where X is the number of soul counters on this artifact. Spend this mana only to cast instant, sorcery, Demon, and Spirit spells.| Mesa Enchantress|Duskmourn: House of Horror Commander|68|R|{1}{W}{W}|Creature - Human Druid|0|2|Whenever you cast an enchantment spell, you may draw a card.| -Moon-Blessed Cleric|Duskmourn: House of Horror Commander|69|U|{2}{W}|Creature - Human Elf Cleric|3|2|Divine Intervention -- When Moon-Blessed Cleric enters, you may search your library for an enchantment card, reveal it, then shuffle and put that card on top.| +Moon-Blessed Cleric|Duskmourn: House of Horror Commander|69|U|{2}{W}|Creature - Human Elf Cleric|3|2|Divine Intervention -- When this creature enters, you may search your library for an enchantment card, reveal it, then shuffle and put that card on top.| Terminus|Duskmourn: House of Horror Commander|70|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| Aminatou's Augury|Duskmourn: House of Horror Commander|71|R|{6}{U}{U}|Sorcery|||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 spell of that type from among the exiled cards without paying its mana cost.| Cackling Counterpart|Duskmourn: House of Horror Commander|72|R|{1}{U}{U}|Instant|||Create a token that's a copy of target creature you control.$Flashback {5}{U}{U}| @@ -55294,13 +55321,13 @@ Night's Whisper|Duskmourn: House of Horror Commander|79|C|{1}{B}|Sorcery|||You d Beast Within|Duskmourn: House of Horror Commander|80|U|{2}{G}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Beast creature token.| Citanul Hierophants|Duskmourn: House of Horror Commander|81|R|{3}{G}|Creature - Human Druid|3|2|Creatures you control have "{T}: Add {G}."| Grapple with the Past|Duskmourn: House of Horror Commander|82|C|{1}{G}|Instant|||Mill three cards, then you may return a creature or land card from your graveyard to your hand.| -Moldgraf Monstrosity|Duskmourn: House of Horror Commander|83|R|{4}{G}{G}{G}|Creature - Insect|8|8|Trample$When Moldgraf Monstrosity dies, exile it, then return two creature cards at random from your graveyard to the battlefield.| +Moldgraf Monstrosity|Duskmourn: House of Horror Commander|83|R|{4}{G}{G}{G}|Creature - Insect|8|8|Trample$When this creature dies, exile it, then return two creature cards at random from your graveyard to the battlefield.| Bedevil|Duskmourn: House of Horror Commander|84|R|{B}{B}{R}|Instant|||Destroy target artifact, creature, or planeswalker.| Culling Ritual|Duskmourn: House of Horror Commander|85|R|{2}{B}{G}|Sorcery|||Destroy each nonland permanent with mana value 2 or less. Add {B} or {G} for each permanent destroyed this way.| Deathreap Ritual|Duskmourn: House of Horror Commander|86|U|{2}{B}{G}|Enchantment|||Morbid -- At the beginning of each end step, if a creature died this turn, you may draw a card.| Diabolic Vision|Duskmourn: House of Horror Commander|87|U|{U}{B}|Sorcery|||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.| Growth Spiral|Duskmourn: House of Horror Commander|88|C|{G}{U}|Instant|||Draw a card. You may put a land card from your hand onto the battlefield.| -Mogis, God of Slaughter|Duskmourn: House of Horror Commander|89|M|{2}{B}{R}|Legendary Enchantment Creature - God|7|5|Indestructible$As long as your devotion to black and red is less than seven, Mogis isn't a creature.$At the beginning of each opponent's upkeep, Mogis deals 2 damage to that player unless they sacrifice a creature.| +Mogis, God of Slaughter|Duskmourn: House of Horror Commander|89|M|{2}{B}{R}|Legendary Enchantment Creature - God|7|5|Indestructible$As long as your devotion to black and red is less than seven, Mogis isn't a creature.$At the beginning of each opponent's upkeep, Mogis deals 2 damage to that player unless they sacrifice a creature of their choice.| Putrefy|Duskmourn: House of Horror Commander|90|U|{1}{B}{G}|Instant|||Destroy target artifact or creature. It can't be regenerated.| Utter End|Duskmourn: House of Horror Commander|91|R|{2}{W}{B}|Instant|||Exile target nonland permanent.| Arcane Signet|Duskmourn: House of Horror Commander|92|C|{2}|Artifact|||{T}: Add one mana of any color in your commander's color identity.| @@ -55308,242 +55335,242 @@ Lightning Greaves|Duskmourn: House of Horror Commander|93|U|{2}|Artifact - Equip Sol Ring|Duskmourn: House of Horror Commander|94|U|{1}|Artifact|||{T}: Add {C}{C}.| Suspicious Bookcase|Duskmourn: House of Horror Commander|95|U|{2}|Artifact Creature - Wall|0|4|Defender${3}, {T}: Target creature can't be blocked this turn.| Command Tower|Duskmourn: House of Horror Commander|96|C||Land|||{T}: Add one mana of any color in your commander's color identity.| -Auramancer|Duskmourn: House of Horror Commander|97|C|{2}{W}|Creature - Human Wizard|2|2|When Auramancer enters, you may return target enchantment card from your graveyard to your hand.| -Cast Out|Duskmourn: House of Horror Commander|98|U|{3}{W}|Enchantment|||Flash$When Cast Out enters, exile target nonland permanent an opponent controls until Cast Out leaves the battlefield.$Cycling {W}| +Auramancer|Duskmourn: House of Horror Commander|97|C|{2}{W}|Creature - Human Wizard|2|2|When this creature enters, you may return target enchantment card from your graveyard to your hand.| +Cast Out|Duskmourn: House of Horror Commander|98|U|{3}{W}|Enchantment|||Flash$When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield.$Cycling {W}| Entreat the Angels|Duskmourn: House of Horror Commander|99|M|{X}{X}{W}{W}{W}|Sorcery|||Create X 4/4 white Angel creature tokens with flying.$Miracle {X}{W}{W}| Monologue Tax|Duskmourn: House of Horror Commander|100|R|{2}{W}|Enchantment|||Whenever an opponent casts their second spell each turn, you create a Treasure token.| Ondu Spiritdancer|Duskmourn: House of Horror Commander|101|R|{4}{W}|Creature - Kor Cleric|3|3|Whenever an enchantment you control enters, you may create a token that's a copy of it. Do this only once each turn.| Return to Dust|Duskmourn: House of Horror Commander|102|U|{2}{W}{W}|Instant|||Exile target artifact or enchantment. If you cast this spell during your main phase, you may exile up to one other target artifact or enchantment.| Sigil of the Empty Throne|Duskmourn: House of Horror Commander|103|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| Sphere of Safety|Duskmourn: House of Horror Commander|104|U|{4}{W}|Enchantment|||Creatures can't attack you or planeswalkers you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control.| -Starfield Mystic|Duskmourn: House of Horror Commander|105|R|{1}{W}|Creature - Human Cleric|2|2|Enchantment spells you cast cost {1} less to cast.$Whenever an enchantment you control is put into a graveyard from the battlefield, put a +1/+1 counter on Starfield Mystic.| +Starfield Mystic|Duskmourn: House of Horror Commander|105|R|{1}{W}|Creature - Human Cleric|2|2|Enchantment spells you cast cost {1} less to cast.$Whenever an enchantment you control is put into a graveyard from the battlefield, put a +1/+1 counter on this creature.| Swords to Plowshares|Duskmourn: House of Horror Commander|106|U|{W}|Instant|||Exile target creature. Its controller gains life equal to its power.| -Timely Ward|Duskmourn: House of Horror Commander|107|R|{2}{W}|Enchantment - Aura|||You may cast Timely Ward as though it had flash if it targets a commander.$Enchant creature$Enchanted creature has indestructible.| +Timely Ward|Duskmourn: House of Horror Commander|107|R|{2}{W}|Enchantment - Aura|||You may cast this spell as though it had flash if it targets a commander.$Enchant creature$Enchanted creature has indestructible.| Verge Rangers|Duskmourn: House of Horror Commander|108|R|{2}{W}|Creature - Human Scout Ranger|3|3|First strike$You may look at the top card of your library any time.$As long as an opponent controls more lands than you, you may play lands from the top of your library.| Aether Gale|Duskmourn: House of Horror Commander|109|R|{3}{U}{U}|Sorcery|||Return six target nonland permanents to their owners' hands.| Arcane Denial|Duskmourn: House of Horror Commander|110|C|{1}{U}|Instant|||Counter target spell. Its controller may draw up to two cards at the beginning of the next turn's upkeep.$You draw a card at the beginning of the next turn's upkeep.| Archetype of Imagination|Duskmourn: House of Horror Commander|111|U|{4}{U}{U}|Enchantment Creature - Human Wizard|3|2|Creatures you control have flying.$Creatures your opponents control lose flying and can't have or gain flying.| -Body of Knowledge|Duskmourn: House of Horror Commander|112|R|{3}{U}{U}|Creature - Avatar|*|*|Body of Knowledge's power and toughness are each equal to the number of cards in your hand.$You have no maximum hand size.$Whenever Body of Knowledge is dealt damage, draw that many cards.| +Body of Knowledge|Duskmourn: House of Horror Commander|112|R|{3}{U}{U}|Creature - Avatar|*|*|Body of Knowledge's power and toughness are each equal to the number of cards in your hand.$You have no maximum hand size.$Whenever this creature is dealt damage, draw that many cards.| Brainstorm|Duskmourn: House of Horror Commander|113|C|{U}|Instant|||Draw three cards, then put two cards from your hand on top of your library in any order.| -Counterspell|Duskmourn: House of Horror Commander|114|C|{U}{U}|Instant|||Counter target spell.| +Counterspell|Duskmourn: House of Horror Commander|114|U|{U}{U}|Instant|||Counter target spell.| Dig Through Time|Duskmourn: House of Horror Commander|115|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.| -Dream Eater|Duskmourn: House of Horror Commander|116|M|{4}{U}{U}|Creature - Nightmare Sphinx|4|3|Flash$Flying$When Dream Eater enters, surveil 4. When you do, you may return target nonland permanent an opponent controls to its owner's hand.| +Dream Eater|Duskmourn: House of Horror Commander|116|M|{4}{U}{U}|Creature - Nightmare Sphinx|4|3|Flash$Flying$When this creature enters, surveil 4. When you do, you may return target nonland permanent an opponent controls to its owner's hand.| Extravagant Replication|Duskmourn: House of Horror Commander|117|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.| -Kefnet the Mindful|Duskmourn: House of Horror Commander|118|M|{2}{U}|Legendary Creature - God|5|5|Flying, indestructible$Kefnet the Mindful can't attack or block unless you have seven or more cards in hand.${3}{U}: Draw a card, then you may return a land you control to its owner's hand.| -Kheru Spellsnatcher|Duskmourn: House of Horror Commander|119|R|{3}{U}|Creature - Snake Wizard|3|3|Morph {4}{U}{U}$When Kheru Spellsnatcher 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 for as long as it remains exiled.| -Mirrormade|Duskmourn: House of Horror Commander|120|R|{1}{U}{U}|Enchantment|||You may have Mirrormade enter as a copy of any artifact or enchantment on the battlefield.| +Kefnet the Mindful|Duskmourn: House of Horror Commander|118|M|{2}{U}|Legendary Creature - God|5|5|Flying, indestructible$Kefnet can't attack or block unless you have seven or more cards in hand.${3}{U}: Draw a card, then you may return a land you control to its owner's hand.| +Kheru Spellsnatcher|Duskmourn: House of Horror Commander|119|R|{3}{U}|Creature - Snake Wizard|3|3|Morph {4}{U}{U}$When this creature 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 for as long as it remains exiled.| +Mirrormade|Duskmourn: House of Horror Commander|120|R|{1}{U}{U}|Enchantment|||You may have this enchantment enter as a copy of any artifact or enchantment on the battlefield.| One with the Multiverse|Duskmourn: House of Horror Commander|121|M|{6}{U}{U}|Enchantment|||You may look at the top card of your library any time.$You may play lands and cast spells from the top of your library.$Once during each of your turns, you may cast a spell from your hand or the top of your library without paying its mana cost.| Otherworldly Gaze|Duskmourn: House of Horror Commander|122|C|{U}|Instant|||Surveil 3.$Flashback {1}{U}| Primordial Mist|Duskmourn: House of Horror Commander|123|R|{4}{U}|Enchantment|||At the beginning of your end step, you may manifest the top card of your library.$Exile a face-down permanent you control face up: You may play that card this turn.| -Prognostic Sphinx|Duskmourn: House of Horror Commander|124|R|{3}{U}{U}|Creature - Sphinx|3|5|Flying$Discard a card: Prognostic Sphinx gains hexproof until end of turn. Tap it.$Whenever Prognostic Sphinx attacks, scry 3.| +Prognostic Sphinx|Duskmourn: House of Horror Commander|124|R|{3}{U}{U}|Creature - Sphinx|3|5|Flying$Discard a card: This creature gains hexproof until end of turn. Tap it.$Whenever this creature attacks, scry 3.| Reality Shift|Duskmourn: House of Horror Commander|125|U|{1}{U}|Instant|||Exile target creature. Its controller manifests the top card of their library.| Retreat to Coralhelm|Duskmourn: House of Horror Commander|126|U|{2}{U}|Enchantment|||Landfall -- Whenever a land you control enters, choose one --$* You may tap or untap target creature.$* Scry 1.| -Shark Typhoon|Duskmourn: House of Horror Commander|127|R|{5}{U}|Enchantment|||Whenever you cast a noncreature spell, create an X/X blue Shark creature token with flying, where X is that spell's mana value.$Cycling {X}{1}{U}$When you cycle Shark Typhoon, create an X/X blue Shark creature token with flying.| -Skaab Ruinator|Duskmourn: House of Horror Commander|128|M|{1}{U}{U}|Creature - Zombie Horror|5|6|As an additional cost to cast this spell, exile three creature cards from your graveyard.$Flying$You may cast Skaab Ruinator from your graveyard.| +Shark Typhoon|Duskmourn: House of Horror Commander|127|R|{5}{U}|Enchantment|||Whenever you cast a noncreature spell, create an X/X blue Shark creature token with flying, where X is that spell's mana value.$Cycling {X}{1}{U}$When you cycle this card, create an X/X blue Shark creature token with flying.| +Skaab Ruinator|Duskmourn: House of Horror Commander|128|M|{1}{U}{U}|Creature - Zombie Horror|5|6|As an additional cost to cast this spell, exile three creature cards from your graveyard.$Flying$You may cast this card from your graveyard.| Thirst for Meaning|Duskmourn: House of Horror Commander|129|C|{2}{U}|Instant|||Draw three cards. Then discard two cards unless you discard an enchantment card.| -Arvinox, the Mind Flail|Duskmourn: House of Horror Commander|130|M|{4}{B}{B}{B}|Legendary Enchantment Creature - Horror|9|9|Arvinox, the Mind Flail isn't a creature unless you control three or more permanents you don't own.$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.| -Bastion of Remembrance|Duskmourn: House of Horror Commander|131|U|{2}{B}|Enchantment|||When Bastion of Remembrance enters, create a 1/1 white Human Soldier creature token.$Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.| -Blood Artist|Duskmourn: House of Horror Commander|132|U|{1}{B}|Creature - Vampire|0|1|Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life.| -Braids, Arisen Nightmare|Duskmourn: House of Horror Commander|133|R|{1}{B}{B}|Legendary Creature - Nightmare|3|3|At the beginning of your end step, you may sacrifice an artifact, creature, enchantment, land, or planeswalker. If you do, each opponent may sacrifice a permanent that shares a card type with it. For each opponent who doesn't, that player loses 2 life and you draw a card.| -Carrion Grub|Duskmourn: House of Horror Commander|134|C|{3}{B}|Creature - Insect|0|5|Carrion Grub gets +X/+0, where X is the greatest power among creature cards in your graveyard.$When Carrion Grub enters, mill four cards.| +Arvinox, the Mind Flail|Duskmourn: House of Horror Commander|130|M|{4}{B}{B}{B}|Legendary Enchantment Creature - Horror|9|9|Arvinox isn't a creature unless you control three or more permanents you don't own.$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.| +Bastion of Remembrance|Duskmourn: House of Horror Commander|131|U|{2}{B}|Enchantment|||When this enchantment enters, create a 1/1 white Human Soldier creature token.$Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.| +Blood Artist|Duskmourn: House of Horror Commander|132|U|{1}{B}|Creature - Vampire|0|1|Whenever this creature or another creature dies, target player loses 1 life and you gain 1 life.| +Braids, Arisen Nightmare|Duskmourn: House of Horror Commander|133|R|{1}{B}{B}|Legendary Creature - Nightmare|3|3|At the beginning of your end step, you may sacrifice an artifact, creature, enchantment, land, or planeswalker. If you do, each opponent may sacrifice a permanent of their choice that shares a card type with it. For each opponent who doesn't, that player loses 2 life and you draw a card.| +Carrion Grub|Duskmourn: House of Horror Commander|134|U|{3}{B}|Creature - Insect|0|5|This creature gets +X/+0, where X is the greatest power among creature cards in your graveyard.$When this creature enters, mill four cards.| Cemetery Tampering|Duskmourn: House of Horror Commander|135|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.| -Decree of Pain|Duskmourn: House of Horror Commander|136|R|{6}{B}{B}|Sorcery|||Destroy all creatures. They can't be regenerated. Draw a card for each creature destroyed this way.$Cycling {3}{B}{B}$When you cycle Decree of Pain, all creatures get -2/-2 until end of turn.| -Demon of Fate's Design|Duskmourn: House of Horror Commander|137|R|{4}{B}{B}|Enchantment Creature - Demon|6|6|Flying, trample$Once during each of your turns, you may cast an enchantment spell by paying life equal to its mana value rather than paying its mana cost.${2}{B}, Sacrifice another enchantment: Demon of Fate's Design gets +X/+0 until end of turn, where X is the sacrificed enchantment's mana value.| -Doomwake Giant|Duskmourn: House of Horror Commander|138|R|{4}{B}|Enchantment Creature - Giant|4|6|Constellation -- Whenever Doomwake Giant or another enchantment you control enters, creatures your opponents control get -1/-1 until end of turn.| -The Eldest Reborn|Duskmourn: House of Horror Commander|139|U|{4}{B}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Each opponent sacrifices a creature or planeswalker.$II -- Each opponent discards a card.$III -- Put target creature or planeswalker card from a graveyard onto the battlefield under your control.| -Falkenrath Noble|Duskmourn: House of Horror Commander|140|U|{3}{B}|Creature - Vampire Noble|2|2|Flying$Whenever Falkenrath Noble or another creature dies, target player loses 1 life and you gain 1 life.| -Fate Unraveler|Duskmourn: House of Horror Commander|141|R|{3}{B}|Enchantment Creature - Hag|3|4|Whenever an opponent draws a card, Fate Unraveler deals 1 damage to that player.| -Gray Merchant of Asphodel|Duskmourn: House of Horror Commander|142|U|{3}{B}{B}|Creature - Zombie|2|4|When Gray Merchant of Asphodel enters, each opponent loses X life, where X is your devotion to black. You gain life equal to the life lost this way.| +Decree of Pain|Duskmourn: House of Horror Commander|136|R|{6}{B}{B}|Sorcery|||Destroy all creatures. They can't be regenerated. Draw a card for each creature destroyed this way.$Cycling {3}{B}{B}$When you cycle this card, all creatures get -2/-2 until end of turn.| +Demon of Fate's Design|Duskmourn: House of Horror Commander|137|R|{4}{B}{B}|Enchantment Creature - Demon|6|6|Flying, trample$Once during each of your turns, you may cast an enchantment spell by paying life equal to its mana value rather than paying its mana cost.${2}{B}, Sacrifice another enchantment: This creature gets +X/+0 until end of turn, where X is the sacrificed enchantment's mana value.| +Doomwake Giant|Duskmourn: House of Horror Commander|138|R|{4}{B}|Enchantment Creature - Giant|4|6|Constellation -- Whenever this creature or another enchantment you control enters, creatures your opponents control get -1/-1 until end of turn.| +The Eldest Reborn|Duskmourn: House of Horror Commander|139|U|{4}{B}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Each opponent sacrifices a creature or planeswalker of their choice.$II -- Each opponent discards a card.$III -- Put target creature or planeswalker card from a graveyard onto the battlefield under your control.| +Falkenrath Noble|Duskmourn: House of Horror Commander|140|C|{3}{B}|Creature - Vampire Noble|2|2|Flying$Whenever this creature or another creature dies, target player loses 1 life and you gain 1 life.| +Fate Unraveler|Duskmourn: House of Horror Commander|141|R|{3}{B}|Enchantment Creature - Hag|3|4|Whenever an opponent draws a card, this creature deals 1 damage to that player.| +Gray Merchant of Asphodel|Duskmourn: House of Horror Commander|142|U|{3}{B}{B}|Creature - Zombie|2|4|When this creature enters, each opponent loses X life, where X is your devotion to black. You gain life equal to the life lost this way.| Infernal Grasp|Duskmourn: House of Horror Commander|143|U|{1}{B}|Instant|||Destroy target creature. You lose 2 life.| -Kederekt Parasite|Duskmourn: House of Horror Commander|144|R|{B}|Creature - Horror|1|1|Whenever an opponent draws a card, if you control a red permanent, you may have Kederekt Parasite deal 1 damage to that player.| +Kederekt Parasite|Duskmourn: House of Horror Commander|144|R|{B}|Creature - Horror|1|1|Whenever an opponent draws a card, if you control a red permanent, you may have this creature deal 1 damage to that player.| Mask of Griselbrand|Duskmourn: House of Horror Commander|145|R|{1}{B}{B}|Legendary Artifact - Equipment|||Equipped creature has flying and lifelink.$Whenever equipped creature dies, you may pay X life, where X is its power. If you do, draw X cards.$Equip {3}| Massacre Girl|Duskmourn: House of Horror Commander|146|R|{3}{B}{B}|Legendary Creature - Human Assassin|4|4|Menace$When Massacre Girl enters, each other creature gets -1/-1 until end of turn. Whenever a creature dies this turn, each creature other than Massacre Girl gets -1/-1 until end of turn.| -Massacre Wurm|Duskmourn: House of Horror Commander|147|M|{3}{B}{B}{B}|Creature - Phyrexian Wurm|6|5|When Massacre Wurm enters, creatures your opponents control get -2/-2 until end of turn.$Whenever a creature an opponent controls dies, that player loses 2 life.| +Massacre Wurm|Duskmourn: House of Horror Commander|147|M|{3}{B}{B}{B}|Creature - Phyrexian Wurm|6|5|When this creature enters, creatures your opponents control get -2/-2 until end of turn.$Whenever a creature an opponent controls dies, that player loses 2 life.| Morbid Opportunist|Duskmourn: House of Horror Commander|148|U|{2}{B}|Creature - Human Rogue|1|3|Whenever one or more other creatures die, draw a card. This ability triggers only once each turn.| Nightmare Shepherd|Duskmourn: House of Horror Commander|149|R|{2}{B}{B}|Enchantment Creature - Demon|4|4|Flying$Whenever another nontoken creature you control dies, you may exile it. If you do, create a token that's a copy of that creature, except it's 1/1 and it's a Nightmare in addition to its other types.| -Nightshade Harvester|Duskmourn: House of Horror Commander|150|R|{3}{B}|Creature - Elf Shaman|2|2|Whenever a land an opponent controls enters, that player loses 1 life. Put a +1/+1 counter on Nightshade Harvester.| -Noxious Gearhulk|Duskmourn: House of Horror Commander|151|M|{4}{B}{B}|Artifact Creature - Construct|5|4|Menace$When Noxious Gearhulk enters, you may destroy another target creature. If a creature is destroyed this way, you gain life equal to its toughness.| +Nightshade Harvester|Duskmourn: House of Horror Commander|150|R|{3}{B}|Creature - Elf Shaman|2|2|Whenever a land an opponent controls enters, that player loses 1 life. Put a +1/+1 counter on this creature.| +Noxious Gearhulk|Duskmourn: House of Horror Commander|151|M|{4}{B}{B}|Artifact Creature - Construct|5|4|Menace$When this creature enters, you may destroy another target creature. If a creature is destroyed this way, you gain life equal to its toughness.| Ob Nixilis Reignited|Duskmourn: House of Horror Commander|152|M|{3}{B}{B}|Legendary Planeswalker - Nixilis|5|+1: You draw a card and you lose 1 life.$-3: Destroy target creature.$-8: Target opponent gets an emblem with "Whenever a player draws a card, you lose 2 life."| Professor Onyx|Duskmourn: House of Horror Commander|153|M|{4}{B}{B}|Legendary Planeswalker - Liliana|5|Magecraft -- Whenever you cast or copy an instant or sorcery spell, each opponent loses 2 life and you gain 2 life.$+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.$-3: Each opponent sacrifices a creature with the greatest power among creatures that player controls.$-8: Each opponent may discard a card. If they don't, they lose 3 life. Repeat this process six more times.| Read the Bones|Duskmourn: House of Horror Commander|154|C|{2}{B}|Sorcery|||Scry 2, then draw two cards. You lose 2 life.| Reanimate|Duskmourn: House of Horror Commander|155|R|{B}|Sorcery|||Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its mana value.| Sign in Blood|Duskmourn: House of Horror Commander|156|C|{B}{B}|Sorcery|||Target player draws two cards and loses 2 life.| -Stitcher's Supplier|Duskmourn: House of Horror Commander|157|U|{B}|Creature - Zombie|1|1|When Stitcher's Supplier enters or dies, mill three cards.| -Syr Konrad, the Grim|Duskmourn: House of Horror Commander|158|U|{3}{B}{B}|Legendary Creature - Human Knight|5|4|Whenever another creature dies, or a creature card is put into a graveyard from anywhere other than the battlefield, or a creature card leaves your graveyard, Syr Konrad, the Grim deals 1 damage to each opponent.${1}{B}: Each player mills a card.| +Stitcher's Supplier|Duskmourn: House of Horror Commander|157|U|{B}|Creature - Zombie|1|1|When this creature enters or dies, mill three cards.| +Syr Konrad, the Grim|Duskmourn: House of Horror Commander|158|U|{3}{B}{B}|Legendary Creature - Human Knight|5|4|Whenever another creature dies, or a creature card is put into a graveyard from anywhere other than the battlefield, or a creature card leaves your graveyard, Syr Konrad deals 1 damage to each opponent.${1}{B}: Each player mills a card.| Whip of Erebos|Duskmourn: House of Horror Commander|159|R|{2}{B}{B}|Legendary Enchantment Artifact|||Creatures you control have lifelink.${2}{B}{B}, {T}: Return target creature card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. If it would leave the battlefield, exile it instead of putting it anywhere else. Activate only as a sorcery.| Blasphemous Act|Duskmourn: House of Horror Commander|160|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.| -Brash Taunter|Duskmourn: House of Horror Commander|161|R|{4}{R}|Creature - Goblin|1|1|Indestructible$Whenever Brash Taunter is dealt damage, it deals that much damage to target opponent.${2}{R}, {T}: Brash Taunter fights another target creature.| +Brash Taunter|Duskmourn: House of Horror Commander|161|R|{4}{R}|Creature - Goblin|1|1|Indestructible$Whenever this creature is dealt damage, it deals that much damage to target opponent.${2}{R}, {T}: This creature fights another target creature.| Chaos Warp|Duskmourn: House of Horror Commander|162|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.| -Combustible Gearhulk|Duskmourn: House of Horror Commander|163|M|{4}{R}{R}|Artifact Creature - Construct|6|6|First strike$When Combustible Gearhulk enters, target opponent may have you draw three cards. If the player doesn't, you mill three cards, then Combustible Gearhulk deals damage to that player equal to the total mana value of those cards.| +Combustible Gearhulk|Duskmourn: House of Horror Commander|163|M|{4}{R}{R}|Artifact Creature - Construct|6|6|First strike$When this creature enters, target opponent may have you draw three cards. If the player doesn't, you mill three cards, then this creature deals damage to that player equal to the total mana value of those cards.| Enchanter's Bane|Duskmourn: House of Horror Commander|164|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its mana value to its controller unless that player sacrifices it.| -Harsh Mentor|Duskmourn: House of Horror Commander|165|R|{1}{R}|Creature - Human Cleric|2|2|Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, Harsh Mentor deals 2 damage to that player.| +Harsh Mentor|Duskmourn: House of Horror Commander|165|R|{1}{R}|Creature - Human Cleric|2|2|Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, if it isn't a mana ability, this creature deals 2 damage to that player.| Light Up the Stage|Duskmourn: House of Horror Commander|166|U|{2}{R}|Sorcery|||Spectacle {R}$Exile the top two cards of your library. Until the end of your next turn, you may play those cards.| -Rampaging Ferocidon|Duskmourn: House of Horror Commander|167|R|{2}{R}|Creature - Dinosaur|3|3|Menace$Players can't gain life.$Whenever another creature enters, Rampaging Ferocidon deals 1 damage to that creature's controller.| -Tectonic Giant|Duskmourn: House of Horror Commander|168|R|{2}{R}{R}|Creature - Elemental Giant|3|4|Whenever Tectonic Giant attacks or becomes the target of a spell an opponent controls, choose one --$* Tectonic Giant deals 3 damage to each opponent.$* Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card.| +Rampaging Ferocidon|Duskmourn: House of Horror Commander|167|R|{2}{R}|Creature - Dinosaur|3|3|Menace$Players can't gain life.$Whenever another creature enters, this creature deals 1 damage to that creature's controller.| +Tectonic Giant|Duskmourn: House of Horror Commander|168|R|{2}{R}{R}|Creature - Elemental Giant|3|4|Whenever this creature attacks or becomes the target of a spell an opponent controls, choose one --$* This creature deals 3 damage to each opponent.$* Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card.| Arachnogenesis|Duskmourn: House of Horror Commander|169|R|{2}{G}|Instant|||Create X 1/2 green Spider creature tokens with reach, where X is the number of creatures attacking you. Prevent all combat damage that would be dealt this turn by non-Spider creatures.| -Ashaya, Soul of the Wild|Duskmourn: House of Horror Commander|170|M|{3}{G}{G}|Legendary Creature - Elemental|*|*|Ashaya, Soul of the Wild's power and toughness are each equal to the number of lands you control.$Nontoken creatures you control are Forest lands in addition to their other types.| +Ashaya, Soul of the Wild|Duskmourn: House of Horror Commander|170|M|{3}{G}{G}|Legendary Creature - Elemental|*|*|Ashaya's power and toughness are each equal to the number of lands you control.$Nontoken creatures you control are Forest lands in addition to their other types.| Augur of Autumn|Duskmourn: House of Horror Commander|171|R|{1}{G}{G}|Creature - Human Druid|2|3|You may look at the top card of your library any time.$You may play lands from the top of your library.$Coven -- As long as you control three or more creatures with different powers, you may cast creature spells from the top of your library.| Beanstalk Giant|Duskmourn: House of Horror Commander|172|U|{6}{G}|Creature - Giant|*|*|Beanstalk Giant's power and toughness are each equal to the number of lands you control.| Fertile Footsteps|Duskmourn: House of Horror Commander|172|U|{2}{G}|Sorcery - Adventure|*|*|Search your library for a basic land card, put it onto the battlefield, then shuffle.| Crawling Sensation|Duskmourn: House of Horror Commander|173|U|{2}{G}|Enchantment|||At the beginning of your upkeep, you may mill two cards.$Whenever one or more land cards are put into your graveyard from anywhere for the first time each turn, create a 1/1 green Insect creature token.| Cultivate|Duskmourn: House of Horror Commander|174|C|{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.| -Deathcap Cultivator|Duskmourn: House of Horror Commander|175|R|{1}{G}|Creature - Human Druid|2|1|{T}: Add {B} or {G}.$Delirium -- Deathcap Cultivator has deathtouch as long as there are four or more card types among cards in your graveyard.| -Deathmist Raptor|Duskmourn: House of Horror Commander|176|M|{1}{G}{G}|Creature - Dinosaur Beast|3|3|Deathtouch$Whenever a permanent you control is turned face up, you may return Deathmist Raptor from your graveyard to the battlefield face up or face down.$Megamorph {4}{G}| +Deathcap Cultivator|Duskmourn: House of Horror Commander|175|R|{1}{G}|Creature - Human Druid|2|1|{T}: Add {B} or {G}.$Delirium -- This creature has deathtouch as long as there are four or more card types among cards in your graveyard.| +Deathmist Raptor|Duskmourn: House of Horror Commander|176|M|{1}{G}{G}|Creature - Dinosaur Beast|3|3|Deathtouch$Whenever a permanent you control is turned face up, you may return this card from your graveyard to the battlefield face up or face down.$Megamorph {4}{G}| Explosive Vegetation|Duskmourn: House of Horror Commander|177|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.| Ezuri's Predation|Duskmourn: House of Horror Commander|178|R|{5}{G}{G}{G}|Sorcery|||For each creature your opponents control, create a 4/4 green Phyrexian Beast creature token. Each of those tokens fights a different one of those creatures.| -Giant Adephage|Duskmourn: House of Horror Commander|179|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.| -Gnarlwood Dryad|Duskmourn: House of Horror Commander|180|U|{G}|Creature - Dryad Horror|1|1|Deathtouch$Delirium -- Gnarlwood Dryad gets +2/+2 as long as there are four or more card types among cards in your graveyard.| -Greater Tanuki|Duskmourn: House of Horror Commander|181|C|{4}{G}{G}|Enchantment Creature - Dog|6|5|Trample$Channel -- {2}{G}, Discard Greater Tanuki: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| +Giant Adephage|Duskmourn: House of Horror Commander|179|M|{5}{G}{G}|Creature - Insect|7|7|Trample$Whenever this creature deals combat damage to a player, create a token that's a copy of this creature.| +Gnarlwood Dryad|Duskmourn: House of Horror Commander|180|U|{G}|Creature - Dryad Horror|1|1|Deathtouch$Delirium -- This creature gets +2/+2 as long as there are four or more card types among cards in your graveyard.| +Greater Tanuki|Duskmourn: House of Horror Commander|181|C|{4}{G}{G}|Enchantment Creature - Dog|6|5|Trample$Channel -- {2}{G}, Discard this card: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| Harmonize|Duskmourn: House of Horror Commander|182|U|{2}{G}{G}|Sorcery|||Draw three cards.| Harrow|Duskmourn: House of Horror Commander|183|C|{2}{G}|Instant|||As an additional cost to cast this spell, sacrifice a land.$Search your library for up to two basic land cards, put them onto the battlefield, then shuffle.| -Hornet Queen|Duskmourn: House of Horror Commander|184|M|{4}{G}{G}{G}|Creature - Insect|2|2|Flying, deathtouch$When Hornet Queen enters, create four 1/1 green Insect creature tokens with flying and deathtouch.| -Hydra Omnivore|Duskmourn: House of Horror Commander|185|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydra Omnivore deals combat damage to an opponent, it deals that much damage to each other opponent.| +Hornet Queen|Duskmourn: House of Horror Commander|184|R|{4}{G}{G}{G}|Creature - Insect|2|2|Flying, deathtouch$When this creature enters, create four 1/1 green Insect creature tokens with flying and deathtouch.| +Hydra Omnivore|Duskmourn: House of Horror Commander|185|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever this creature deals combat damage to an opponent, it deals that much damage to each other opponent.| Inscription of Abundance|Duskmourn: House of Horror Commander|186|R|{1}{G}|Instant|||Kicker {2}{G}$Choose one. If this spell was kicked, choose any number instead.$* Put two +1/+1 counters on target creature.$* Target player gains X life, where X is the greatest power among creatures they control.$* Target creature you control fights target creature you don't control.| -Ishkanah, Grafwidow|Duskmourn: House of Horror Commander|187|M|{4}{G}|Legendary Creature - Spider|3|5|Reach$Delirium -- When Ishkanah, Grafwidow enters, if there are four or more card types among cards in your graveyard, create three 1/2 green Spider creature tokens with reach.${6}{B}: Target opponent loses 1 life for each Spider you control.| -Moldgraf Millipede|Duskmourn: House of Horror Commander|188|C|{4}{G}|Creature - Insect Horror|2|2|When Moldgraf Millipede enters, mill three cards, then put a +1/+1 counter on Moldgraf Millipede for each creature card in your graveyard.| +Ishkanah, Grafwidow|Duskmourn: House of Horror Commander|187|M|{4}{G}|Legendary Creature - Spider|3|5|Reach$Delirium -- When Ishkanah enters, if there are four or more card types among cards in your graveyard, create three 1/2 green Spider creature tokens with reach.${6}{B}: Target opponent loses 1 life for each Spider you control.| +Moldgraf Millipede|Duskmourn: House of Horror Commander|188|C|{4}{G}|Creature - Insect Horror|2|2|When this creature enters, mill three cards, then put a +1/+1 counter on this creature for each creature card in your graveyard.| Mulch|Duskmourn: House of Horror Commander|189|C|{1}{G}|Sorcery|||Reveal the top four cards of your library. Put all land cards revealed this way into your hand and the rest into your graveyard.| -Multani, Yavimaya's Avatar|Duskmourn: House of Horror Commander|190|M|{4}{G}{G}|Legendary Creature - Elemental Avatar|0|0|Reach, trample$Multani, Yavimaya's Avatar gets +1/+1 for each land you control and each land card in your graveyard.${1}{G}, Return two lands you control to their owner's hand: Return Multani from your graveyard to your hand.| -Obsessive Skinner|Duskmourn: House of Horror Commander|191|U|{1}{G}|Creature - Human Rogue|1|1|When Obsessive Skinner enters, put a +1/+1 counter on target creature.$Delirium -- At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, put a +1/+1 counter on target creature.| +Multani, Yavimaya's Avatar|Duskmourn: House of Horror Commander|190|M|{4}{G}{G}|Legendary Creature - Elemental Avatar|0|0|Reach, trample$Multani gets +1/+1 for each land you control and each land card in your graveyard.${1}{G}, Return two lands you control to their owner's hand: Return this card from your graveyard to your hand.| +Obsessive Skinner|Duskmourn: House of Horror Commander|191|U|{1}{G}|Creature - Human Rogue|1|1|When this creature enters, put a +1/+1 counter on target creature.$Delirium -- At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, put a +1/+1 counter on target creature.| Overwhelming Stampede|Duskmourn: House of Horror Commander|192|R|{3}{G}{G}|Sorcery|||Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control.| Rampant Growth|Duskmourn: House of Horror Commander|193|C|{1}{G}|Sorcery|||Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.| -Sakura-Tribe Elder|Duskmourn: House of Horror Commander|194|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.| +Sakura-Tribe Elder|Duskmourn: House of Horror Commander|194|C|{1}{G}|Creature - Snake Shaman|1|1|Sacrifice this creature: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.| Sandwurm Convergence|Duskmourn: House of Horror Commander|195|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|Duskmourn: House of Horror Commander|196|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|Duskmourn: House of Horror Commander|197|R|{2}{G}|Creature - Insect|1|1|Landfall -- Whenever a land you control enters, 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.| -Shigeki, Jukai Visionary|Duskmourn: House of Horror Commander|198|R|{1}{G}|Legendary Enchantment Creature - Snake Druid|1|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.$Channel -- {X}{X}{G}{G}, Discard Shigeki: Return X target nonlegendary cards from your graveyard to your hand.| +Scavenging Ooze|Duskmourn: House of Horror Commander|196|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 this creature and you gain 1 life.| +Scute Swarm|Duskmourn: House of Horror Commander|197|R|{2}{G}|Creature - Insect|1|1|Landfall -- Whenever a land you control enters, create a 1/1 green Insect creature token. If you control six or more lands, create a token that's a copy of this creature instead.| +Shigeki, Jukai Visionary|Duskmourn: House of Horror Commander|198|R|{1}{G}|Legendary Enchantment Creature - Snake Druid|1|3|{1}{G}, {T}, Return Shigeki 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.$Channel -- {X}{X}{G}{G}, Discard this card: Return X target nonlegendary cards from your graveyard to your hand.| Skola Grovedancer|Duskmourn: House of Horror Commander|199|C|{1}{G}|Enchantment Creature - Satyr Druid|2|2|Whenever a land card is put into your graveyard from anywhere, you gain 1 life.${2}{G}: Mill a card.| -Temur War Shaman|Duskmourn: House of Horror Commander|200|R|{4}{G}{G}|Creature - Human Shaman|4|5|When Temur War Shaman enters, manifest the top card of your library.$Whenever a permanent you control is turned face up, if it's a creature, you may have it fight target creature you don't control.| -Thunderfoot Baloth|Duskmourn: House of Horror Commander|201|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.| +Temur War Shaman|Duskmourn: House of Horror Commander|200|R|{4}{G}{G}|Creature - Human Shaman|4|5|When this creature enters, manifest the top card of your library.$Whenever a permanent you control is turned face up, if it's a creature, you may have it fight target creature you don't control.| +Thunderfoot Baloth|Duskmourn: House of Horror Commander|201|R|{4}{G}{G}|Creature - Beast|5|5|Trample$Lieutenant -- As long as you control your commander, this creature gets +2/+2 and other creatures you control get +2/+2 and have trample.| Titania, Nature's Force|Duskmourn: House of Horror Commander|202|M|{4}{G}{G}|Legendary Creature - Elemental|6|6|You may play Forests from your graveyard.$Whenever a Forest you control enters, create a 5/3 green Elemental creature token.$Whenever an Elemental you control dies, you may mill three cards.| Trail of Mystery|Duskmourn: House of Horror Commander|203|R|{1}{G}|Enchantment|||Whenever a face-down creature you control enters, you may search your library for a basic land card, reveal it, put it into your hand, then shuffle.$Whenever a permanent you control is turned face up, if it's a creature, it gets +2/+2 until end of turn.| -Whisperwood Elemental|Duskmourn: House of Horror Commander|204|M|{3}{G}{G}|Creature - Elemental|4|4|At the beginning of your end step, manifest the top card of your library.$Sacrifice Whisperwood Elemental: Until end of turn, face-up nontoken creatures you control gain "When this creature dies, manifest the top card of your library."| +Whisperwood Elemental|Duskmourn: House of Horror Commander|204|M|{3}{G}{G}|Creature - Elemental|4|4|At the beginning of your end step, manifest the top card of your library.$Sacrifice this creature: Until end of turn, face-up nontoken creatures you control gain "When this creature dies, manifest the top card of your library."| Wilderness Reclamation|Duskmourn: House of Horror Commander|205|U|{3}{G}|Enchantment|||At the beginning of your end step, untap all lands you control.| -Worldspine Wurm|Duskmourn: House of Horror Commander|206|M|{8}{G}{G}{G}|Creature - Wurm|15|15|Trample$When Worldspine Wurm dies, create three 5/5 green Wurm creature tokens with trample.$When Worldspine Wurm is put into a graveyard from anywhere, shuffle it into its owner's library.| -Wrenn and Seven|Duskmourn: House of Horror Commander|207|M|{3}{G}{G}|Legendary Planeswalker - Wrenn|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.$0: Put any number of land cards from your hand onto the battlefield tapped.$-3: Create a green Treefolk creature token with reach and "This creature's power and toughness are each equal to the number of lands you control."$-8: Return all permanent cards from your graveyard to your hand. You get an emblem with "You have no maximum hand size."| -Yavimaya Elder|Duskmourn: House of Horror Commander|208|C|{1}{G}{G}|Creature - Human Druid|2|1|When Yavimaya Elder dies, you may search your library for up to two basic land cards, reveal them, put them into your hand, then shuffle.${2}, Sacrifice Yavimaya Elder: Draw a card.| +Worldspine Wurm|Duskmourn: House of Horror Commander|206|M|{8}{G}{G}{G}|Creature - Wurm|15|15|Trample$When this creature dies, create three 5/5 green Wurm creature tokens with trample.$When Worldspine Wurm is put into a graveyard from anywhere, shuffle it into its owner's library.| +Wrenn and Seven|Duskmourn: House of Horror Commander|207|M|{3}{G}{G}|Legendary Planeswalker - Wrenn|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.$0: Put any number of land cards from your hand onto the battlefield tapped.$-3: Create a green Treefolk creature token with reach and "This token's power and toughness are each equal to the number of lands you control."$-8: Return all permanent cards from your graveyard to your hand. You get an emblem with "You have no maximum hand size."| +Yavimaya Elder|Duskmourn: House of Horror Commander|208|C|{1}{G}{G}|Creature - Human Druid|2|1|When this creature dies, you may search your library for up to two basic land cards, reveal them, put them into your hand, then shuffle.${2}, Sacrifice this creature: Draw a card.| Yedora, Grave Gardener|Duskmourn: House of Horror Commander|209|U|{4}{G}|Legendary Creature - Treefolk Druid|5|5|Whenever another nontoken creature you control dies, you may return it to the battlefield face down under its owner's control. It's a Forest land.| Aesi, Tyrant of Gyre Strait|Duskmourn: House of Horror Commander|210|M|{4}{G}{U}|Legendary Creature - Serpent|5|5|You may play an additional land on each of your turns.$Landfall -- Whenever a land you control enters, you may draw a card.| -Arixmethes, Slumbering Isle|Duskmourn: House of Horror Commander|211|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| +Arixmethes, Slumbering Isle|Duskmourn: House of Horror Commander|211|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes enters tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| Athreos, Shroud-Veiled|Duskmourn: House of Horror Commander|212|M|{4}{W}{B}|Legendary Enchantment Creature - God|4|7|Indestructible$As long as your devotion to white and black is less than seven, Athreos isn't a creature.$At the beginning of your end step, put a coin counter on another target creature.$Whenever a creature with a coin counter on it dies or is put into exile, return that card to the battlefield under your control.| Binding the Old Gods|Duskmourn: House of Horror Commander|213|U|{2}{B}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Destroy target nonland permanent an opponent controls.$II -- Search your library for a Forest card, put it onto the battlefield tapped, then shuffle.$III -- Creatures you control gain deathtouch until end of turn.| Biomass Mutation|Duskmourn: House of Horror Commander|214|R|{X}{G/U}{G/U}|Instant|||Creatures you control have base power and toughness X/X until end of turn.| -Deadbridge Chant|Duskmourn: House of Horror Commander|215|M|{4}{B}{G}|Enchantment|||When Deadbridge Chant enters, mill ten cards.$At the beginning of your upkeep, choose a card at random in your graveyard. If it's a creature card, return it to the battlefield. Otherwise, return it to your hand.| +Deadbridge Chant|Duskmourn: House of Horror Commander|215|M|{4}{B}{G}|Enchantment|||When this enchantment enters, mill ten cards.$At the beginning of your upkeep, choose a card at random in your graveyard. If it's a creature card, put it onto the battlefield. Otherwise, put it into your hand.| Eureka Moment|Duskmourn: House of Horror Commander|216|C|{2}{G}{U}|Instant|||Draw two cards. You may put a land card from your hand onto the battlefield.| -Florian, Voldaren Scion|Duskmourn: House of Horror Commander|217|R|{1}{B}{R}|Legendary Creature - Vampire Noble|3|3|First strike$At the beginning of your second main phase, look at the top X cards of your library, where X is the total amount of life your opponents lost this turn. Exile one of those cards and put the rest on the bottom of your library in a random order. You may play the exiled card this turn.| -Grim Flayer|Duskmourn: House of Horror Commander|218|R|{B}{G}|Creature - Human Warrior|2|2|Trample$Whenever Grim Flayer deals combat damage to a player, surveil 3.$Delirium -- Grim Flayer gets +2/+2 as long as there are four or more card types among cards in your graveyard.| +Florian, Voldaren Scion|Duskmourn: House of Horror Commander|217|R|{1}{B}{R}|Legendary Creature - Vampire Noble|3|3|First strike$At the beginning of each of your postcombat main phases, look at the top X cards of your library, where X is the total amount of life your opponents lost this turn. Exile one of those cards and put the rest on the bottom of your library in a random order. You may play the exiled card this turn.| +Grim Flayer|Duskmourn: House of Horror Commander|218|M|{B}{G}|Creature - Human Warrior|2|2|Trample$Whenever this creature deals combat damage to a player, surveil 3.$Delirium -- This creature gets +2/+2 as long as there are four or more card types among cards in your graveyard.| Grisly Salvage|Duskmourn: House of Horror Commander|219|C|{B}{G}|Instant|||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.| -Grist, the Hunger Tide|Duskmourn: House of Horror Commander|220|M|{1}{B}{G}|Legendary Planeswalker - Grist|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.$+1: Create a 1/1 black and green Insect creature token, then mill a card. If an Insect card was milled this way, put a loyalty counter on Grist and repeat this process.$-2: You may sacrifice a creature. When you do, destroy target creature or planeswalker.$-5: Each opponent loses life equal to the number of creature cards in your graveyard.| +Grist, the Hunger Tide|Duskmourn: House of Horror Commander|220|M|{1}{B}{G}|Legendary Planeswalker - Grist|3|As long as Grist isn't on the battlefield, it's a 1/1 Insect creature in addition to its other types.$+1: Create a 1/1 black and green Insect creature token, then mill a card. If an Insect card was milled this way, put a loyalty counter on Grist and repeat this process.$-2: You may sacrifice a creature. When you do, destroy target creature or planeswalker.$-5: Each opponent loses life equal to the number of creature cards in your graveyard.| Inkshield|Duskmourn: House of Horror Commander|221|R|{3}{W}{B}|Instant|||Prevent all combat damage that would be dealt to you this turn. For each 1 damage prevented this way, create a 2/1 white and black Inkling creature token with flying.| -Kaervek the Merciless|Duskmourn: House of Horror Commander|222|R|{5}{B}{R}|Legendary Creature - Human Shaman|5|4|Whenever an opponent casts a spell, Kaervek the Merciless deals damage equal to that spell's mana value to any target.| -Kardur, Doomscourge|Duskmourn: House of Horror Commander|223|U|{2}{B}{R}|Legendary Creature - Demon Berserker|4|3|When Kardur, Doomscourge enters, until your next turn, creatures your opponents control attack each combat if able and attack a player other than you if able.$Whenever an attacking creature dies, each opponent loses 1 life and you gain 1 life.| +Kaervek the Merciless|Duskmourn: House of Horror Commander|222|R|{5}{B}{R}|Legendary Creature - Human Shaman|5|4|Whenever an opponent casts a spell, Kaervek deals damage equal to that spell's mana value to any target.| +Kardur, Doomscourge|Duskmourn: House of Horror Commander|223|U|{2}{B}{R}|Legendary Creature - Demon Berserker|4|3|When Kardur enters, until your next turn, creatures your opponents control attack each combat if able and attack a player other than you if able.$Whenever an attacking creature dies, each opponent loses 1 life and you gain 1 life.| Life Insurance|Duskmourn: House of Horror Commander|224|R|{3}{W}{B}|Enchantment|||Extort$Whenever a nontoken creature dies, you lose 1 life and create a Treasure token.| -Mayhem Devil|Duskmourn: House of Horror Commander|225|U|{1}{B}{R}|Creature - Devil|3|3|Whenever a player sacrifices a permanent, Mayhem Devil deals 1 damage to any target.| -Nyx Weaver|Duskmourn: House of Horror Commander|226|U|{1}{B}{G}|Enchantment Creature - Spider|2|3|Reach$At the beginning of your upkeep, mill two cards.${1}{B}{G}, Exile Nyx Weaver: Return target card from your graveyard to your hand.| +Mayhem Devil|Duskmourn: House of Horror Commander|225|U|{1}{B}{R}|Creature - Devil|3|3|Whenever a player sacrifices a permanent, this creature deals 1 damage to any target.| +Nyx Weaver|Duskmourn: House of Horror Commander|226|U|{1}{B}{G}|Enchantment Creature - Spider|2|3|Reach$At the beginning of your upkeep, mill two cards.${1}{B}{G}, Exile this creature: Return target card from your graveyard to your hand.| Old Stickfingers|Duskmourn: House of Horror Commander|227|R|{X}{B}{G}|Legendary Creature - Horror|*|*|When you cast this spell, reveal cards from the top of your library until you reveal X creature cards. Put all creature cards revealed this way into your graveyard, then put the rest on the bottom of your library in a random order.$Old Stickfingers's power and toughness are each equal to the number of creature cards in your graveyard.| Oversimplify|Duskmourn: House of Horror Commander|228|R|{3}{G}{U}|Sorcery|||Exile all creatures. Each player creates a 0/0 green and blue Fractal creature token and puts a number of +1/+1 counters on it equal to the total power of creatures they controlled that were exiled this way.| Rakdos Charm|Duskmourn: House of Horror Commander|229|U|{B}{R}|Instant|||Choose one --$* Exile target player's graveyard.$* Destroy target artifact.$* Each creature deals 1 damage to its controller.| -Rakdos, Lord of Riots|Duskmourn: House of Horror Commander|230|M|{B}{B}{R}{R}|Legendary Creature - Demon|6|6|You can't cast this spell unless an opponent lost life this turn.$Flying, trample$Creature spells you cast cost {1} less to cast for each 1 life your opponents have lost this turn.| +Rakdos, Lord of Riots|Duskmourn: House of Horror Commander|230|M|{B}{B}{R}{R}|Legendary Creature - Demon|6|6|You can't cast Rakdos unless an opponent lost life this turn.$Flying, trample$Creature spells you cast cost {1} less to cast for each 1 life your opponents have lost this turn.| Rashmi, Eternities Crafter|Duskmourn: House of Horror Commander|231|M|{2}{G}{U}|Legendary Creature - Elf Druid|2|3|Whenever you cast your first spell each turn, reveal the top card of your library. You may cast it without paying its mana cost if it's a spell with lesser mana value. If you don't cast it, put it into your hand.| Spirit-Sister's Call|Duskmourn: House of Horror Commander|232|M|{3}{W}{B}|Enchantment|||At the beginning of your end step, choose target permanent card in your graveyard. You may sacrifice a permanent that shares a card type with the chosen card. If you do, return the chosen card from your graveyard to the battlefield and it gains "If this permanent would leave the battlefield, exile it instead of putting it anywhere else."| -Spiteful Visions|Duskmourn: House of Horror Commander|233|R|{2}{B/R}{B/R}|Enchantment|||At the beginning of each player's draw step, that player draws an additional card.$Whenever a player draws a card, Spiteful Visions deals 1 damage to that player.| +Spiteful Visions|Duskmourn: House of Horror Commander|233|R|{2}{B/R}{B/R}|Enchantment|||At the beginning of each player's draw step, that player draws an additional card.$Whenever a player draws a card, this enchantment deals 1 damage to that player.| Stormfist Crusader|Duskmourn: House of Horror Commander|234|R|{B}{R}|Creature - Human Knight|2|2|Menace$At the beginning of your upkeep, each player draws a card and loses 1 life.| Tatyova, Benthic Druid|Duskmourn: House of Horror Commander|235|U|{3}{G}{U}|Legendary Creature - Merfolk Druid|3|3|Landfall -- Whenever a land you control enters, you gain 1 life and draw a card.| -Theater of Horrors|Duskmourn: House of Horror Commander|236|R|{1}{B}{R}|Enchantment|||At the beginning of your upkeep, exile the top card of your library.$During your turn, if an opponent lost life this turn, you may play lands and cast spells from among cards exiled with Theater of Horrors.${3}{R}: Theater of Horrors deals 1 damage to target opponent or planeswalker.| +Theater of Horrors|Duskmourn: House of Horror Commander|236|R|{1}{B}{R}|Enchantment|||At the beginning of your upkeep, exile the top card of your library.$During your turn, if an opponent lost life this turn, you may play lands and cast spells from among cards exiled with this enchantment.${3}{R}: This enchantment deals 1 damage to target opponent or planeswalker.| Time Wipe|Duskmourn: House of Horror Commander|237|R|{2}{W}{W}{U}|Sorcery|||Return a creature you control to its owner's hand, then destroy all creatures.| -Trygon Predator|Duskmourn: House of Horror Commander|238|U|{1}{G}{U}|Creature - Beast|2|3|Flying$Whenever Trygon Predator deals combat damage to a player, you may destroy target artifact or enchantment that player controls.| -Vial Smasher the Fierce|Duskmourn: House of Horror Commander|239|M|{1}{B}{R}|Legendary Creature - Goblin Berserker|2|3|Whenever you cast your first spell each turn, choose an opponent at random. Vial Smasher the Fierce deals damage equal to that spell's mana value to that player or a planeswalker that player controls.$Partner| +Trygon Predator|Duskmourn: House of Horror Commander|238|U|{1}{G}{U}|Creature - Beast|2|3|Flying$Whenever this creature deals combat damage to a player, you may destroy target artifact or enchantment that player controls.| +Vial Smasher the Fierce|Duskmourn: House of Horror Commander|239|M|{1}{B}{R}|Legendary Creature - Goblin Berserker|2|3|Whenever you cast your first spell each turn, choose an opponent at random. Vial Smasher deals damage equal to that spell's mana value to that player or a planeswalker that player controls.$Partner| Azorius Signet|Duskmourn: House of Horror Commander|240|U|{2}|Artifact|||{1}, {T}: Add {W}{U}.| Basilisk Collar|Duskmourn: House of Horror Commander|241|R|{1}|Artifact - Equipment|||Equipped creature has deathtouch and lifelink.$Equip {2}| -Brainstone|Duskmourn: House of Horror Commander|242|U|{1}|Artifact|||{2}, {T}, Sacrifice Brainstone: Draw three cards, then put two cards from your hand on top of your library in any order.| -Burnished Hart|Duskmourn: House of Horror Commander|243|U|{3}|Artifact Creature - Elk|2|2|{3}, Sacrifice Burnished Hart: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.| -Commander's Sphere|Duskmourn: House of Horror Commander|244|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice Commander's Sphere: Draw a card.| +Brainstone|Duskmourn: House of Horror Commander|242|U|{1}|Artifact|||{2}, {T}, Sacrifice this artifact: Draw three cards, then put two cards from your hand on top of your library in any order.| +Burnished Hart|Duskmourn: House of Horror Commander|243|U|{3}|Artifact Creature - Elk|2|2|{3}, Sacrifice this creature: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.| +Commander's Sphere|Duskmourn: House of Horror Commander|244|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice this artifact: Draw a card.| Fellwar Stone|Duskmourn: House of Horror Commander|245|U|{2}|Artifact|||{T}: Add one mana of any color that a land an opponent controls could produce.| -Golgari Signet|Duskmourn: House of Horror Commander|246|C|{2}|Artifact|||{1}, {T}: Add {B}{G}.| -Haywire Mite|Duskmourn: House of Horror Commander|247|U|{1}|Artifact Creature - Insect|1|1|When Haywire Mite dies, you gain 2 life.${G}, Sacrifice Haywire Mite: Exile target noncreature artifact or noncreature enchantment.| -Mind Stone|Duskmourn: House of Horror Commander|248|U|{2}|Artifact|||{T}: Add {C}.${1}, {T}, Sacrifice Mind Stone: Draw a card.| +Golgari Signet|Duskmourn: House of Horror Commander|246|U|{2}|Artifact|||{1}, {T}: Add {B}{G}.| +Haywire Mite|Duskmourn: House of Horror Commander|247|U|{1}|Artifact Creature - Insect|1|1|When this creature dies, you gain 2 life.${G}, Sacrifice this creature: Exile target noncreature artifact or noncreature enchantment.| +Mind Stone|Duskmourn: House of Horror Commander|248|U|{2}|Artifact|||{T}: Add {C}.${1}, {T}, Sacrifice this artifact: Draw a card.| Orzhov Signet|Duskmourn: House of Horror Commander|249|U|{2}|Artifact|||{1}, {T}: Add {W}{B}.| Rakdos Signet|Duskmourn: House of Horror Commander|250|U|{2}|Artifact|||{1}, {T}: Add {B}{R}.| Scroll of Fate|Duskmourn: House of Horror Commander|251|R|{3}|Artifact|||{T}: Manifest a card from your hand.| Simic Signet|Duskmourn: House of Horror Commander|252|U|{2}|Artifact|||{1}, {T}: Add {G}{U}.| -Solemn Simulacrum|Duskmourn: House of Horror Commander|253|R|{4}|Artifact Creature - Golem|2|2|When Solemn Simulacrum enters, 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.| -Talisman of Indulgence|Duskmourn: House of Horror Commander|254|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {R}. Talisman of Indulgence deals 1 damage to you.| -Talisman of Resilience|Duskmourn: House of Horror Commander|255|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {G}. Talisman of Resilience deals 1 damage to you.| -Thought Vessel|Duskmourn: House of Horror Commander|256|U|{2}|Artifact|||You have no maximum hand size.${T}: Add {C}.| +Solemn Simulacrum|Duskmourn: House of Horror Commander|253|R|{4}|Artifact Creature - Golem|2|2|When this creature enters, you may search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.$When this creature dies, you may draw a card.| +Talisman of Indulgence|Duskmourn: House of Horror Commander|254|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {R}. This artifact deals 1 damage to you.| +Talisman of Resilience|Duskmourn: House of Horror Commander|255|U|{2}|Artifact|||{T}: Add {C}.${T}: Add {B} or {G}. This artifact deals 1 damage to you.| +Thought Vessel|Duskmourn: House of Horror Commander|256|C|{2}|Artifact|||You have no maximum hand size.${T}: Add {C}.| Whispersilk Cloak|Duskmourn: House of Horror Commander|257|U|{3}|Artifact - Equipment|||Equipped creature can't be blocked and has shroud.$Equip {2}| -Adarkar Wastes|Duskmourn: House of Horror Commander|258|R||Land|||{T}: Add {C}.${T}: Add {W} or {U}. Adarkar Wastes deals 1 damage to you.| -Arcane Sanctum|Duskmourn: House of Horror Commander|259|U||Land|||Arcane Sanctum enters tapped.${T}: Add {W}, {U}, or {B}.| +Adarkar Wastes|Duskmourn: House of Horror Commander|258|R||Land|||{T}: Add {C}.${T}: Add {W} or {U}. This land deals 1 damage to you.| +Arcane Sanctum|Duskmourn: House of Horror Commander|259|U||Land|||This land enters tapped.${T}: Add {W}, {U}, or {B}.| Ash Barrens|Duskmourn: House of Horror Commander|260|C||Land|||{T}: Add {C}.$Basic landcycling {1}| -Azorius Chancery|Duskmourn: House of Horror Commander|261|U||Land|||Azorius Chancery enters tapped.$When Azorius Chancery enters, return a land you control to its owner's hand.${T}: Add {W}{U}.| -Barren Moor|Duskmourn: House of Horror Commander|262|U||Land|||Barren Moor enters tapped.${T}: Add {B}.$Cycling {B}| -Blackcleave Cliffs|Duskmourn: House of Horror Commander|263|R||Land|||Blackcleave Cliffs enters tapped unless you control two or fewer other lands.${T}: Add {B} or {R}.| -Bloodfell Caves|Duskmourn: House of Horror Commander|264|C||Land|||Bloodfell Caves enters tapped.$When Bloodfell Caves enters, you gain 1 life.${T}: Add {B} or {R}.| -Bojuka Bog|Duskmourn: House of Horror Commander|265|C||Land|||Bojuka Bog enters tapped.$When Bojuka Bog enters, exile target player's graveyard.${T}: Add {B}.| -Canyon Slough|Duskmourn: House of Horror Commander|266|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$Canyon Slough enters tapped.$Cycling {2}| -Castle Vantress|Duskmourn: House of Horror Commander|267|R||Land|||Castle Vantress enters tapped unless you control an Island.${T}: Add {U}.${2}{U}{U}, {T}: Scry 2.| -Caves of Koilos|Duskmourn: House of Horror Commander|268|R||Land|||{T}: Add {C}.${T}: Add {W} or {B}. Caves of Koilos deals 1 damage to you.| -Darkmoss Bridge|Duskmourn: House of Horror Commander|269|C||Artifact Land|||Darkmoss Bridge enters tapped.$Indestructible${T}: Add {B} or {G}.| -Dimir Aqueduct|Duskmourn: House of Horror Commander|270|U||Land|||Dimir Aqueduct enters tapped.$When Dimir Aqueduct enters, return a land you control to its owner's hand.${T}: Add {U}{B}.| -Dragonskull Summit|Duskmourn: House of Horror Commander|271|R||Land|||Dragonskull Summit enters tapped unless you control a Swamp or a Mountain.${T}: Add {B} or {R}.| -Drownyard Temple|Duskmourn: House of Horror Commander|272|R||Land|||{T}: Add {C}.${3}: Return Drownyard Temple from your graveyard to the battlefield tapped.| -Dryad Arbor|Duskmourn: House of Horror Commander|273|R||Land Creature - Forest Dryad|1|1|(Dryad Arbor isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G}.")| -Evolving Wilds|Duskmourn: House of Horror Commander|274|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| +Azorius Chancery|Duskmourn: House of Horror Commander|261|U||Land|||This land enters tapped.$When this land enters, return a land you control to its owner's hand.${T}: Add {W}{U}.| +Barren Moor|Duskmourn: House of Horror Commander|262|U||Land|||This land enters tapped.${T}: Add {B}.$Cycling {B}| +Blackcleave Cliffs|Duskmourn: House of Horror Commander|263|R||Land|||This land enters tapped unless you control two or fewer other lands.${T}: Add {B} or {R}.| +Bloodfell Caves|Duskmourn: House of Horror Commander|264|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {B} or {R}.| +Bojuka Bog|Duskmourn: House of Horror Commander|265|C||Land|||This land enters tapped.$When this land enters, exile target player's graveyard.${T}: Add {B}.| +Canyon Slough|Duskmourn: House of Horror Commander|266|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$This land enters tapped.$Cycling {2}| +Castle Vantress|Duskmourn: House of Horror Commander|267|R||Land|||This land enters tapped unless you control an Island.${T}: Add {U}.${2}{U}{U}, {T}: Scry 2.| +Caves of Koilos|Duskmourn: House of Horror Commander|268|R||Land|||{T}: Add {C}.${T}: Add {W} or {B}. This land deals 1 damage to you.| +Darkmoss Bridge|Duskmourn: House of Horror Commander|269|C||Artifact Land|||This land enters tapped.$Indestructible${T}: Add {B} or {G}.| +Dimir Aqueduct|Duskmourn: House of Horror Commander|270|U||Land|||This land enters tapped.$When this land enters, return a land you control to its owner's hand.${T}: Add {U}{B}.| +Dragonskull Summit|Duskmourn: House of Horror Commander|271|R||Land|||This land enters tapped unless you control a Swamp or a Mountain.${T}: Add {B} or {R}.| +Drownyard Temple|Duskmourn: House of Horror Commander|272|R||Land|||{T}: Add {C}.${3}: Return this card from your graveyard to the battlefield tapped.| +Dryad Arbor|Duskmourn: House of Horror Commander|273|R||Land Creature - Forest Dryad|1|1|(This land isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G}.")| +Evolving Wilds|Duskmourn: House of Horror Commander|274|C||Land|||{T}, Sacrifice this land: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| Exotic Orchard|Duskmourn: House of Horror Commander|275|R||Land|||{T}: Add one mana of any color that a land an opponent controls could produce.| Flooded Grove|Duskmourn: House of Horror Commander|276|R||Land|||{T}: Add {C}.${G/U}, {T}: Add {G}{G}, {G}{U}, or {U}{U}.| -Foreboding Ruins|Duskmourn: House of Horror Commander|277|R||Land|||As Foreboding Ruins enters, you may reveal a Swamp or Mountain card from your hand. If you don't, Foreboding Ruins enters tapped.${T}: Add {B} or {R}.| -Geothermal Bog|Duskmourn: House of Horror Commander|278|C||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$Geothermal Bog enters tapped.| -Golgari Rot Farm|Duskmourn: House of Horror Commander|279|C||Land|||Golgari Rot Farm enters tapped.$When Golgari Rot Farm enters, return a land you control to its owner's hand.${T}: Add {B}{G}.| +Foreboding Ruins|Duskmourn: House of Horror Commander|277|R||Land|||As this land enters, you may reveal a Swamp or Mountain card from your hand. If you don't, this land enters tapped.${T}: Add {B} or {R}.| +Geothermal Bog|Duskmourn: House of Horror Commander|278|C||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$This land enters tapped.| +Golgari Rot Farm|Duskmourn: House of Horror Commander|279|U||Land|||This land enters tapped.$When this land enters, return a land you control to its owner's hand.${T}: Add {B}{G}.| Graven Cairns|Duskmourn: House of Horror Commander|280|R||Land|||{T}: Add {C}.${B/R}, {T}: Add {B}{B}, {B}{R}, or {R}{R}.| Grim Backwoods|Duskmourn: House of Horror Commander|281|R||Land|||{T}: Add {C}.${2}{B}{G}, {T}, Sacrifice a creature: Draw a card.| -Halimar Depths|Duskmourn: House of Horror Commander|282|C||Land|||Halimar Depths enters tapped.$When Halimar Depths enters, look at the top three cards of your library, then put them back in any order.${T}: Add {U}.| +Halimar Depths|Duskmourn: House of Horror Commander|282|C||Land|||This land enters tapped.$When this land enters, look at the top three cards of your library, then put them back in any order.${T}: Add {U}.| Hall of Heliod's Generosity|Duskmourn: House of Horror Commander|283|R||Legendary Land|||{T}: Add {C}.${1}{W}, {T}: Put target enchantment card from your graveyard on top of your library.| -Hinterland Harbor|Duskmourn: House of Horror Commander|284|R||Land|||Hinterland Harbor enters tapped unless you control a Forest or an Island.${T}: Add {G} or {U}.| -Jungle Hollow|Duskmourn: House of Horror Commander|285|C||Land|||Jungle Hollow enters tapped.$When Jungle Hollow enters, you gain 1 life.${T}: Add {B} or {G}.| -Leechridden Swamp|Duskmourn: House of Horror Commander|286|U||Land - Swamp|||({T}: Add {B}.)$Leechridden Swamp enters tapped.${B}, {T}: Each opponent loses 1 life. Activate only if you control two or more black permanents.| -Llanowar Wastes|Duskmourn: House of Horror Commander|287|R||Land|||{T}: Add {C}.${T}: Add {B} or {G}. Llanowar Wastes deals 1 damage to you.| -Mosswort Bridge|Duskmourn: House of Horror Commander|288|R||Land|||Hideaway 4$Mosswort Bridge enters tapped.${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|Duskmourn: House of Horror Commander|289|U||Land|||Myriad Landscape enters 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.| -Necroblossom Snarl|Duskmourn: House of Horror Commander|290|R||Land|||As Necroblossom Snarl enters, you may reveal a Swamp or Forest card from your hand. If you don't, Necroblossom Snarl enters tapped.${T}: Add {B} or {G}.| -Obscura Storefront|Duskmourn: House of Horror Commander|291|C||Land|||When Obscura Storefront enters, 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.| -Orzhov Basilica|Duskmourn: House of Horror Commander|292|U||Land|||Orzhov Basilica enters tapped.$When Orzhov Basilica enters, return a land you control to its owner's hand.${T}: Add {W}{B}.| +Hinterland Harbor|Duskmourn: House of Horror Commander|284|R||Land|||This land enters tapped unless you control a Forest or an Island.${T}: Add {G} or {U}.| +Jungle Hollow|Duskmourn: House of Horror Commander|285|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {B} or {G}.| +Leechridden Swamp|Duskmourn: House of Horror Commander|286|U||Land - Swamp|||({T}: Add {B}.)$This land enters tapped.${B}, {T}: Each opponent loses 1 life. Activate only if you control two or more black permanents.| +Llanowar Wastes|Duskmourn: House of Horror Commander|287|R||Land|||{T}: Add {C}.${T}: Add {B} or {G}. This land deals 1 damage to you.| +Mosswort Bridge|Duskmourn: House of Horror Commander|288|R||Land|||Hideaway 4$This land enters tapped.${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|Duskmourn: House of Horror Commander|289|U||Land|||This land enters tapped.${T}: Add {C}.${2}, {T}, Sacrifice this land: Search your library for up to two basic land cards that share a land type, put them onto the battlefield tapped, then shuffle.| +Necroblossom Snarl|Duskmourn: House of Horror Commander|290|R||Land|||As this land enters, you may reveal a Swamp or Forest card from your hand. If you don't, this land enters tapped.${T}: Add {B} or {G}.| +Obscura Storefront|Duskmourn: House of Horror Commander|291|C||Land|||When this land enters, 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.| +Orzhov Basilica|Duskmourn: House of Horror Commander|292|U||Land|||This land enters tapped.$When this land enters, return a land you control to its owner's hand.${T}: Add {W}{B}.| Overflowing Basin|Duskmourn: House of Horror Commander|293|R||Land|||{1}, {T}: Add {G}{U}.| -Quandrix Campus|Duskmourn: House of Horror Commander|294|C||Land|||Quandrix Campus enters tapped.${T}: Add {G} or {U}.${4}, {T}: Scry 1.| +Quandrix Campus|Duskmourn: House of Horror Commander|294|C||Land|||This land enters tapped.${T}: Add {G} or {U}.${4}, {T}: Scry 1.| Reliquary Tower|Duskmourn: House of Horror Commander|295|U||Land|||You have no maximum hand size.${T}: Add {C}.| Shadowblood Ridge|Duskmourn: House of Horror Commander|296|R||Land|||{1}, {T}: Add {B}{R}.| Shivan Gorge|Duskmourn: House of Horror Commander|297|R||Legendary Land|||{T}: Add {C}.${2}{R}, {T}: Shivan Gorge deals 1 damage to each opponent.| -Simic Growth Chamber|Duskmourn: House of Horror Commander|298|U||Land|||Simic Growth Chamber enters tapped.$When Simic Growth Chamber enters, return a land you control to its owner's hand.${T}: Add {G}{U}.| -Smoldering Marsh|Duskmourn: House of Horror Commander|299|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$Smoldering Marsh enters tapped unless you control two or more basic lands.| -Spinerock Knoll|Duskmourn: House of Horror Commander|300|R||Land|||Hideaway 4$Spinerock Knoll enters tapped.${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.| -Sulfurous Springs|Duskmourn: House of Horror Commander|301|R||Land|||{T}: Add {C}.${T}: Add {B} or {R}. Sulfurous Springs deals 1 damage to you.| +Simic Growth Chamber|Duskmourn: House of Horror Commander|298|U||Land|||This land enters tapped.$When this land enters, return a land you control to its owner's hand.${T}: Add {G}{U}.| +Smoldering Marsh|Duskmourn: House of Horror Commander|299|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$This land enters tapped unless you control two or more basic lands.| +Spinerock Knoll|Duskmourn: House of Horror Commander|300|R||Land|||Hideaway 4$This land enters tapped.${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.| +Sulfurous Springs|Duskmourn: House of Horror Commander|301|R||Land|||{T}: Add {C}.${T}: Add {B} or {R}. This land deals 1 damage to you.| Tainted Field|Duskmourn: House of Horror Commander|302|U||Land|||{T}: Add {C}.${T}: Add {W} or {B}. Activate only if you control a Swamp.| Tainted Isle|Duskmourn: House of Horror Commander|303|U||Land|||{T}: Add {C}.${T}: Add {U} or {B}. Activate only if you control a Swamp.| Tainted Peak|Duskmourn: House of Horror Commander|304|U||Land|||{T}: Add {C}.${T}: Add {B} or {R}. Activate only if you control a Swamp.| Tainted Wood|Duskmourn: House of Horror Commander|305|U||Land|||{T}: Add {C}.${T}: Add {B} or {G}. Activate only if you control a Swamp.| -Tangled Islet|Duskmourn: House of Horror Commander|306|C||Land - Forest Island|||({T}: Add {G} or {U}.)$Tangled Islet enters tapped.| -Temple of Deceit|Duskmourn: House of Horror Commander|307|R||Land|||Temple of Deceit enters tapped.$When Temple of Deceit enters, scry 1.${T}: Add {U} or {B}.| -Temple of Enlightenment|Duskmourn: House of Horror Commander|308|R||Land|||Temple of Enlightenment enters tapped.$When Temple of Enlightenment enters, scry 1.${T}: Add {W} or {U}.| -Temple of Malady|Duskmourn: House of Horror Commander|309|R||Land|||Temple of Malady enters tapped.$When Temple of Malady enters, scry 1.${T}: Add {B} or {G}.| -Temple of Malice|Duskmourn: House of Horror Commander|310|R||Land|||Temple of Malice enters tapped.$When Temple of Malice enters, scry 1.${T}: Add {B} or {R}.| -Temple of Mystery|Duskmourn: House of Horror Commander|311|R||Land|||Temple of Mystery enters tapped.$When Temple of Mystery enters, scry 1.${T}: Add {G} or {U}.| -Temple of Silence|Duskmourn: House of Horror Commander|312|R||Land|||Temple of Silence enters tapped.$When Temple of Silence enters, scry 1.${T}: Add {W} or {B}.| +Tangled Islet|Duskmourn: House of Horror Commander|306|C||Land - Forest Island|||({T}: Add {G} or {U}.)$This land enters tapped.| +Temple of Deceit|Duskmourn: House of Horror Commander|307|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {U} or {B}.| +Temple of Enlightenment|Duskmourn: House of Horror Commander|308|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {W} or {U}.| +Temple of Malady|Duskmourn: House of Horror Commander|309|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {B} or {G}.| +Temple of Malice|Duskmourn: House of Horror Commander|310|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {B} or {R}.| +Temple of Mystery|Duskmourn: House of Horror Commander|311|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {G} or {U}.| +Temple of Silence|Duskmourn: House of Horror Commander|312|R||Land|||This land enters tapped.$When this land enters, scry 1.${T}: Add {W} or {B}.| Temple of the False God|Duskmourn: House of Horror Commander|313|U||Land|||{T}: Add {C}{C}. Activate only if you control five or more lands.| -Thornwood Falls|Duskmourn: House of Horror Commander|314|C||Land|||Thornwood Falls enters tapped.$When Thornwood Falls enters, you gain 1 life.${T}: Add {G} or {U}.| -Thriving Heath|Duskmourn: House of Horror Commander|315|C||Land|||Thriving Heath enters tapped. As it enters, choose a color other than white.${T}: Add {W} or one mana of the chosen color.| -Thriving Isle|Duskmourn: House of Horror Commander|316|C||Land|||Thriving Isle enters tapped. As it enters, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.| -Thriving Moor|Duskmourn: House of Horror Commander|317|C||Land|||Thriving Moor enters tapped. As it enters, choose a color other than black.${T}: Add {B} or one mana of the chosen color.| -Tranquil Thicket|Duskmourn: House of Horror Commander|318|C||Land|||Tranquil Thicket enters tapped.${T}: Add {G}.$Cycling {G}| +Thornwood Falls|Duskmourn: House of Horror Commander|314|C||Land|||This land enters tapped.$When this land enters, you gain 1 life.${T}: Add {G} or {U}.| +Thriving Heath|Duskmourn: House of Horror Commander|315|C||Land|||This land enters tapped. As it enters, choose a color other than white.${T}: Add {W} or one mana of the chosen color.| +Thriving Isle|Duskmourn: House of Horror Commander|316|C||Land|||This land enters tapped. As it enters, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.| +Thriving Moor|Duskmourn: House of Horror Commander|317|C||Land|||This land enters tapped. As it enters, choose a color other than black.${T}: Add {B} or one mana of the chosen color.| +Tranquil Thicket|Duskmourn: House of Horror Commander|318|C||Land|||This land enters tapped.${T}: Add {G}.$Cycling {G}| Tree of Tales|Duskmourn: House of Horror Commander|319|C||Artifact Land|||{T}: Add {G}.| Twilight Mire|Duskmourn: House of Horror Commander|320|R||Land|||{T}: Add {C}.${B/G}, {T}: Add {B}{B}, {B}{G}, or {G}{G}.| -Underground River|Duskmourn: House of Horror Commander|321|R||Land|||{T}: Add {C}.${T}: Add {U} or {B}. Underground River deals 1 damage to you.| +Underground River|Duskmourn: House of Horror Commander|321|R||Land|||{T}: Add {C}.${T}: Add {U} or {B}. This land deals 1 damage to you.| Vault of Whispers|Duskmourn: House of Horror Commander|322|C||Artifact Land|||{T}: Add {B}.| -Vineglimmer Snarl|Duskmourn: House of Horror Commander|323|R||Land|||As Vineglimmer Snarl enters, you may reveal a Forest or Island card from your hand. If you don't, Vineglimmer Snarl enters tapped.${T}: Add {G} or {U}.| +Vineglimmer Snarl|Duskmourn: House of Horror Commander|323|R||Land|||As this land enters, you may reveal a Forest or Island card from your hand. If you don't, this land enters tapped.${T}: Add {G} or {U}.| Viridescent Bog|Duskmourn: House of Horror Commander|324|R||Land|||{1}, {T}: Add {B}{G}.| Witch's Clinic|Duskmourn: House of Horror Commander|325|R||Land|||{T}: Add {C}.${2}, {T}: Target commander gains lifelink until end of turn.| -Woodland Cemetery|Duskmourn: House of Horror Commander|326|R||Land|||Woodland Cemetery enters tapped unless you control a Swamp or a Forest.${T}: Add {B} or {G}.| -Yavimaya Coast|Duskmourn: House of Horror Commander|327|R||Land|||{T}: Add {C}.${T}: Add {G} or {U}. Yavimaya Coast deals 1 damage to you.| +Woodland Cemetery|Duskmourn: House of Horror Commander|326|R||Land|||This land enters tapped unless you control a Swamp or a Forest.${T}: Add {B} or {G}.| +Yavimaya Coast|Duskmourn: House of Horror Commander|327|R||Land|||{T}: Add {C}.${T}: Add {G} or {U}. This land deals 1 damage to you.| Crypt Ghast|Duskmourn: House of Horror Commander|368|M|{3}{B}|Creature - Spirit|2|2|Extort$Whenever you tap a Swamp for mana, add an additional {B}.| Damn|Duskmourn: House of Horror Commander|369|M|{B}{B}|Sorcery|||Destroy target creature. A creature destroyed this way can't be regenerated.$Overload {2}{W}{W}| Exhume|Duskmourn: House of Horror Commander|370|M|{1}{B}|Sorcery|||Each player puts a creature card from their graveyard onto the battlefield.| -Archon of Cruelty|Duskmourn: House of Horror Commander|371|M|{6}{B}{B}|Creature - Archon|6|6|Flying$Whenever Archon of Cruelty enters or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life.| +Archon of Cruelty|Duskmourn: House of Horror Commander|371|M|{6}{B}{B}|Creature - Archon|6|6|Flying$Whenever this creature enters or attacks, target opponent sacrifices a creature or planeswalker of their choice, discards a card, and loses 3 life. You draw a card and gain 3 life.| Goryo's Vengeance|Duskmourn: House of Horror Commander|372|M|{1}{B}|Instant - Arcane|||Return target legendary creature card from your graveyard to the battlefield. That creature gains haste. Exile it at the beginning of the next end step.$Splice onto Arcane {2}{B}| Living Death|Duskmourn: House of Horror Commander|373|M|{3}{B}{B}|Sorcery|||Each player exiles all creature cards from their graveyard, then sacrifices all creatures they control, then puts all cards they exiled this way onto the battlefield.| Celestial Vault|Alchemy: New Capenna|1|U|{1}{W}|Artifact|||{W}, {T}: Draft a card from Celestial Vault's spellbook and exile it face down.${1}, Sacrifice Celestial Vault: Put each card exiled with Celestial Vault into your hand.| @@ -59761,91 +59788,294 @@ Twilight Mire|Edge of Eternities Commander|189|R||Land|||{T}: Add {C}.${B/G}, {T Viridescent Bog|Edge of Eternities Commander|190|R||Land|||{1}, {T}: Add {B}{G}.| Wastes|Edge of Eternities Commander|191|C||Basic Land|||{T}: Add {C}.| Aang's Journey|Avatar: The Last Airbender|1|C|{2}|Sorcery - Lesson|||Kicker {2}$Search your library for a basic land card. If this spell was kicked, instead search your library for a basic land card and a Shrine card. Reveal those cards, put them into your hand, then shuffle.$You gain 2 life.| +Energybending|Avatar: The Last Airbender|2|U|{2}|Instant - Lesson|||Lands you control gain all basic land types until end of turn.$Draw a card.| +Zuko's Exile|Avatar: The Last Airbender|3|C|{5}|Instant - Lesson|||Exile target artifact, creature, or enchantment. Its controller creates a Clue token.| Aang, the Last Airbender|Avatar: The Last Airbender|4|U|{3}{W}|Legendary Creature - Human Avatar Ally|3|2|Flying$When Aang enters, airbend up to one other target nonland permanent.$Whenever you cast a Lesson spell, Aang gains lifelink until end of turn.| Aang's Iceberg|Avatar: The Last Airbender|5|R|{2}{W}|Enchantment|||Flash$When this enchantment enters, exile up to one other target nonland permanent until this enchantment leaves the battlefield.$Waterbend {3}: Sacrifice this enchantment. If you do, scry 2.| +Airbender Ascension|Avatar: The Last Airbender|6|R|{1}{W}|Enchantment|||When this enchantment enters, airbend up to one target creature.$Whenever a creature you control enters, put a quest counter on this enchantment.$At the beginning of your end step, if this enchantment has four or more quest counters on it, exile up to one target creature you control, then return it to the battlefield under its owner's control.| +Airbender's Reversal|Avatar: The Last Airbender|7|U|{1}{W}|Instant - Lesson|||Choose one --$* Destroy target attacking creature.$* Airbend target creature you control.| Airbending Lesson|Avatar: The Last Airbender|8|C|{2}{W}|Instant - Lesson|||Airbend target nonland permanent.$Draw a card.| +Appa, Loyal Sky Bison|Avatar: The Last Airbender|9|U|{4}{W}{W}|Legendary Creature - Bison Ally|4|4|Flying$Whenever Appa enters or attacks, choose one --$* Target creature you control gains flying until end of turn.$* Airbend another target nonland permanent you control.| Appa, Steadfast Guardian|Avatar: The Last Airbender|10|M|{2}{W}{W}|Legendary Creature - Bison Ally|3|4|Flash$Flying$When Appa enters, airbend any number of other target nonland permanents you control.$Whenever you cast a spell from exile, create a 1/1 white Ally creature token.| Avatar Enthusiasts|Avatar: The Last Airbender|11|C|{2}{W}|Creature - Human Peasant Ally|2|2|Whenever another Ally you control enters, put a +1/+1 counter on this creature.| +Avatar's Wrath|Avatar: The Last Airbender|12|R|{2}{W}{W}|Sorcery|||Choose up to one target creature, then airbend all other creatures.$Until your next turn, your opponents can't cast spells from anywhere other than their hand.$Exile Avatar's Wrath.| +Compassionate Healer|Avatar: The Last Airbender|13|C|{1}{W}|Creature - Human Cleric Ally|2|2|Whenever this creature becomes tapped, you gain 1 life and scry 1.| +Curious Farm Animals|Avatar: The Last Airbender|14|C|{W}|Creature - Boar Elk Bird Ox|1|1|When this creature dies, you gain 3 life.${2}, Sacrifice this creature: Destroy up to one target artifact or enchantment.| +Destined Confrontation|Avatar: The Last Airbender|15|U|{2}{W}{W}|Sorcery|||Each player chooses any number of creatures they control with total power 4 or less, then sacrifices all other creatures they control.| +Earth Kingdom Jailer|Avatar: The Last Airbender|16|U|{2}{W}|Creature - Human Soldier Ally|3|3|When this creature enters, exile up to one target artifact, creature, or enchantment an opponent controls with mana value 3 or greater until this creature leaves the battlefield.| +Earth Kingdom Protectors|Avatar: The Last Airbender|17|U|{W}|Creature - Human Soldier Ally|1|1|Vigilance$Sacrifice this creature: Another target Ally you control gains indestructible until end of turn.| +Enter the Avatar State|Avatar: The Last Airbender|18|U|{W}|Instant - Lesson|||Until end of turn, target creature you control becomes an Avatar in addition to its other types and gains flying, first strike, lifelink, and hexproof.| +Fancy Footwork|Avatar: The Last Airbender|19|U|{2}{W}|Instant - Lesson|||Untap one or two target creatures. They each get +2/+2 until end of turn.| +Gather the White Lotus|Avatar: The Last Airbender|20|U|{4}{W}|Sorcery|||Create a 1/1 white Ally creature token for each Plains you control. Scry 2.| Glider Kids|Avatar: The Last Airbender|21|C|{2}{W}|Creature - Human Pilot Ally|2|3|Flying$When this creature enters, scry 1.| +Glider Staff|Avatar: The Last Airbender|22|U|{2}{W}|Artifact - Equipment|||When this Equipment enters, airbend up to one target creature.$Equipped creature gets +1/+1 and has flying.$Equip {2}| +Hakoda, Selfless Commander|Avatar: The Last Airbender|23|R|{3}{W}|Legendary Creature - Human Warrior Ally|3|5|Vigilance$You may look at the top card of your library any time.$You may cast Ally spells from the top of your library.$Sacrifice Hakoda: Creatures you control get +0/+5 and gain indestructible until end of turn.| +Invasion Reinforcements|Avatar: The Last Airbender|24|U|{1}{W}|Creature - Human Warrior Ally|1|1|Flash$When this creature enters, create a 1/1 white Ally creature token.| Jeong Jeong's Deserters|Avatar: The Last Airbender|25|C|{1}{W}|Creature - Human Rebel Ally|1|2|When this creature enters, put a +1/+1 counter on target creature.| +Kyoshi Warriors|Avatar: The Last Airbender|26|C|{3}{W}|Creature - Human Warrior Ally|3|3|When this creature enters, create a 1/1 white Ally creature token.| +The Legend of Yangchen|Avatar: The Last Airbender|27|M|{3}{W}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I -- Starting with you, each player chooses up to one permanent with mana value 3 or greater from among permanents your opponents control. Exile those permanents.$II -- You may have target opponent draw three cards. If you do, draw three cards.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Yangchen|Avatar: The Last Airbender|27|M||Legendary Creature - Avatar|4|5|Flying$Whenever you cast your second spell each turn, airbend up to one other target nonland permanent.| Master Piandao|Avatar: The Last Airbender|28|U|{4}{W}|Legendary Creature - Human Warrior Ally|4|4|First strike$Whenever Master Piandao attacks, look at the top four cards of your library. You may reveal an Ally, Equipment, or Lesson card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| Momo, Friendly Flier|Avatar: The Last Airbender|29|R|{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$The first non-Lemur creature spell with flying you cast during each of your turns costs {1} less to cast.$Whenever another creature you control with flying enters, Momo gets +1/+1 until end of turn.| +Momo, Playful Pet|Avatar: The Last Airbender|30|U|{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying, vigilance$When Momo leaves the battlefield, choose one --$* Create a Food token.$* Put a +1/+1 counter on target creature you control.$* Scry 2.| Path to Redemption|Avatar: The Last Airbender|31|C|{1}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't attack or block.${5}, Sacrifice this Aura: Exile enchanted creature. Create a 1/1 white Ally creature token. Activate only during your turn.| Rabaroo Troop|Avatar: The Last Airbender|32|C|{3}{W}{W}|Creature - Rabbit Kangaroo|3|5|Landfall -- Whenever a land you control enters, this creature gains flying until end of turn and you gain 1 life.$Plainscycling {2}| Razor Rings|Avatar: The Last Airbender|33|C|{1}{W}|Instant|||Razor Rings deals 4 damage to target attacking or blocking creature. You gain life equal to the excess damage dealt this way.| +Sandbenders' Storm|Avatar: The Last Airbender|34|C|{3}{W}|Instant|||Choose one--$* Destroy target creature with power 4 or greater.$* Earthbend 3.| +South Pole Voyager|Avatar: The Last Airbender|35|R|{1}{W}|Creature - Human Scout Ally|2|2|Whenever this creature or another Ally you control enters, you gain 1 life. If this is the second time this ability has resolved this turn, draw a card.| Southern Air Temple|Avatar: The Last Airbender|36|U|{3}{W}|Legendary Enchantment - Shrine|||When Southern Air Temple enters, put X +1/+1 counters on each creature you control, where X is the number of Shrines you control.$Whenever another Shrine you control enters, put a +1/+1 counter on each creature you control.| +Suki, Courageous Rescuer|Avatar: The Last Airbender|37|R|{1}{W}{W}|Legendary Creature - Human Warrior Ally|2|4|Other creatures you control get +1/+0.$Whenever another permanent you control leaves the battlefield during your turn, create a 1/1 white Ally creature token. This ability triggers only once each turn.| +Team Avatar|Avatar: The Last Airbender|38|U|{2}{W}|Enchantment|||Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of creatures you control.${2}{W}, Discard this card: It deals damage equal to the number of creatures you control to target creature.| +United Front|Avatar: The Last Airbender|39|M|{X}{W}{W}|Sorcery|||Create X 1/1 white Ally creature tokens, then put a +1/+1 counter on each creature you control.| +Vengeful Villagers|Avatar: The Last Airbender|40|U|{3}{W}|Creature - Human Citizen|3|3|Whenever this creature attacks, choose target creature an opponent controls. Tap it, then you may sacrifice an artifact or creature. If you do, put a stun counter on the chosen creature.| +Water Tribe Captain|Avatar: The Last Airbender|41|C|{2}{W}|Creature - Human Soldier Ally|3|3|{5}: Creatures you control get +1/+1 until end of turn.| +Water Tribe Rallier|Avatar: The Last Airbender|42|U|{1}{W}|Creature - Human Soldier Ally|2|2|Waterbend {5}: Look at the top four cards of your library. You may reveal a creature card with power 3 or less from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Yip Yip!|Avatar: The Last Airbender|43|C|{W}|Instant - Lesson|||Target creature you control gets +2/+2 until end of turn. If that creature is an Ally, it also gains flying until end of turn.| +Accumulate Wisdom|Avatar: The Last Airbender|44|U|{1}{U}|Instant - Lesson|||Look at the top three cards of your library. Put one of those cards into your hand and the rest on the bottom of your library in any order. Put each of those cards into your hand instead if there are three or more Lesson cards in your graveyard.| +Benevolent River Spirit|Avatar: The Last Airbender|45|U|{U}{U}|Creature - Spirit|4|5|As an additional cost to cast this spell, waterbend {5}.$Flying, ward {2}$When this creature enters, scry 2.| +Boomerang Basics|Avatar: The Last Airbender|46|U|{U}|Sorcery - Lesson|||Return target nonland permanent to its owner's hand. If you controlled that permanent, draw a card.| +Crashing Wave|Avatar: The Last Airbender|47|U|{U}{U}|Sorcery|||As an additional cost to cast this spell, waterbend {X}.$Tap up to X target creatures, then distribute three stun counters among tapped creatures your opponents control.| +Ember Island Production|Avatar: The Last Airbender|48|U|{3}{U}{U}|Sorcery|||Choose one--$* Create a token that's a copy of target creature you control, except it's not legendary and it's a 4/4 Hero in addition to its other types.$* Create a token that's a copy of target creature an opponent controls, except it's not legendary and it's a 2/2 Coward in addition to its other types.| First-Time Flyer|Avatar: The Last Airbender|49|C|{1}{U}|Creature - Human Pilot Ally|1|2|Flying$This creature gets +1/+1 as long as there's a Lesson card in your graveyard.| Flexible Waterbender|Avatar: The Last Airbender|50|C|{3}{U}|Creature - Human Warrior Ally|2|5|Vigilance$Waterbend {3}: This creature has base power and toughness 5/2 until end of turn.| +Forecasting Fortune Teller|Avatar: The Last Airbender|51|C|{1}{U}|Creature - Human Advisor Ally|1|3|When this creature enters, create a Clue token.| Geyser Leaper|Avatar: The Last Airbender|52|C|{4}{U}|Creature - Human Warrior Ally|4|3|Flying$Waterbend {4}: Draw a card, then discard a card.| Giant Koi|Avatar: The Last Airbender|53|C|{4}{U}{U}|Creature - Fish|5|7|Waterbend {3}: This creature can't be blocked this turn.$Islandcycling {2}| +Gran-Gran|Avatar: The Last Airbender|54|U|{U}|Legendary Creature - Human Peasant Ally|1|2|Whenever Gran-Gran becomes tapped, draw a card, then discard a card.$Noncreature spells you cast cost {1} less to cast as long as there are three or more Lesson cards in your graveyard.| +Honest Work|Avatar: The Last Airbender|55|U|{U}|Enchantment - Aura|||Enchant creature an opponent controls$When this Aura enters, tap enchanted creature and remove all counters from it.$Enchanted creature loses all abilities and is a Citizen with base power and toughness 1/1 and "{T}: Add {C}" named Humble Merchant.| Iguana Parrot|Avatar: The Last Airbender|56|C|{2}{U}|Creature - Lizard Bird Pirate|2|2|Flying, vigilance$Prowess| +Invasion Submersible|Avatar: The Last Airbender|57|U|{2}{U}|Artifact - Vehicle|0|0|When this Vehicle enters, return up to one other target nonland permanent to its owner's hand.$Exhaust -- Waterbend {3}: This Vehicle becomes an artifact creature. Put three +1/+1 counters on it.| It'll Quench Ya!|Avatar: The Last Airbender|58|C|{1}{U}|Instant - Lesson|||Counter target spell unless its controller pays {2}.| Katara, Bending Prodigy|Avatar: The Last Airbender|59|U|{2}{U}|Legendary Creature - Human Warrior Ally|2|3|At the beginning of your end step, if Katara is tapped, put a +1/+1 counter on her.$Waterbend {6}: Draw a card.| +Knowledge Seeker|Avatar: The Last Airbender|60|U|{1}{U}|Creature - Fox Spirit|2|1|Vigilance$Whenever you draw your second card each turn, put a +1/+1 counter on this creature.$When this creature dies, create a Clue token.| +The Legend of Kuruk|Avatar: The Last Airbender|61|M|{2}{U}{U}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I, II -- Scry 2, then draw a card.$III -- Exile this Saga, then return it to the battlefield$transformed under your control.| +Avatar Kuruk|Avatar: The Last Airbender|61|M||Legendary Creature - Avatar|4|3|Whenever you cast a spell, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."$Exhaust -- Waterbend {20}: Take an extra turn after this one.| +Lost Days|Avatar: The Last Airbender|62|C|{4}{U}|Instant - Lesson|||The owner of target creature or enchantment puts it into their library second from the top or on the bottom. You create a Clue token.| Master Pakku|Avatar: The Last Airbender|63|U|{1}{U}|Legendary Creature - Human Advisor Ally|1|3|Prowess$Whenever Master Pakku becomes tapped, target player mills X cards, where X is the number of Lesson cards in your graveyard.| +The Mechanist, Aerial Artisan|Avatar: The Last Airbender|64|R|{2}{U}|Legendary Creature - Human Artificer Ally|1|3|Whenever you cast a noncreature spell, create a Clue token.${T}: Until end of turn, target artifact token you control becomes a 3/1 Construct artifact creature with flying.| +North Pole Patrol|Avatar: The Last Airbender|65|U|{2}{U}|Creature - Human Soldier Ally|2|3|{T}: Untap another target permanent you control.$Waterbend {3}, {T}: Tap target creature an opponent controls.| +Octopus Form|Avatar: The Last Airbender|66|C|{U}|Instant - Lesson|||Target creature you control gets +1/+1 and gains hexproof until end of turn. Untap it.| Otter-Penguin|Avatar: The Last Airbender|67|C|{1}{U}|Creature - Otter Bird|2|1|Whenever you draw your second card each turn, this creature gets +1/+2 until end of turn and can't be blocked this turn.| Rowdy Snowballers|Avatar: The Last Airbender|68|C|{2}{U}|Creature - Human Peasant Ally|2|2|When this creature enters, tap target creature an opponent controls and put a stun counter on it.| +Secret of Bloodbending|Avatar: The Last Airbender|69|M|{U}{U}{U}{U}|Sorcery - Lesson|||As an additional cost to cast this spell, you may waterbend {10}.$You control target opponent during their next combat phase. If this spell's additional cost was paid, you control that player during their next turn instead.$Exile Secret of Bloodbending.| Serpent of the Pass|Avatar: The Last Airbender|70|U|{5}{U}{U}|Creature - Serpent|6|5|If there are three or more Lesson cards in your graveyard, you may cast this spell as though it had flash.$This spell costs {1} less to cast for each noncreature, nonland card in your graveyard.| Sokka's Haiku|Avatar: The Last Airbender|71|U|{3}{U}{U}|Instant - Lesson|||Counter target spell.$Draw a card, then mill three cards.$Untap target land.| +The Spirit Oasis|Avatar: The Last Airbender|72|U|{2}{U}|Legendary Enchantment - Shrine|||When The Spirit Oasis enters, draw a card for each Shrine you control.$Whenever another Shrine you control enters, draw a card.| +Spirit Water Revival|Avatar: The Last Airbender|73|R|{1}{U}{U}|Sorcery|||As an additional cost to cast this spell, you may waterbend {6}.$Draw two cards. If this spell's additional cost was paid, instead shuffle your graveyard into your library, draw seven cards, and you have no maximum hand size for the rest of the game.$Exile Spirit Water Revival.| +Teo, Spirited Glider|Avatar: The Last Airbender|74|U|{3}{U}|Legendary Creature - Human Pilot Ally|1|4|Flying$Whenever one or more creatures you control with flying attack, draw a card, then discard a card. When you discard a nonland card this way, put a +1/+1 counter on target creature you control.| +Tiger-Seal|Avatar: The Last Airbender|75|R|{U}|Creature - Cat Seal|3|3|Vigilance$At the beginning of your upkeep, tap this creature.$Whenever you draw your second card each turn, untap this creature.| +Ty Lee, Chi Blocker|Avatar: The Last Airbender|76|R|{2}{U}|Legendary Creature - Human Performer Ally|2|1|Flash$Prowess$When Ty Lee enters, tap up to one target creature. It doesn't untap during its controller's untap step for as long as you control Ty Lee.| +The Unagi of Kyoshi Island|Avatar: The Last Airbender|77|R|{3}{U}{U}|Legendary Creature - Serpent|5|5|Flash$Ward--Waterbend {4}$Whenever an opponent draws their second card each turn, draw two cards.| +Wan Shi Tong, Librarian|Avatar: The Last Airbender|78|M|{X}{U}{U}|Legendary Creature - Bird Spirit|1|1|Flash$Flying, vigilance$When Wan Shi Tong enters, put X +1/+1 counters on him. Then draw half X cards, rounded down.$Whenever an opponent searches their library, put a +1/+1 counter on Wan Shi Tong and draw a card.| +Waterbender Ascension|Avatar: The Last Airbender|79|R|{1}{U}|Enchantment|||Whenever a creature you control deals combat damage to a player, put a quest counter on this enchantment. Then if it has four or more quest counters on it, draw a card.$Waterbend {4}: Target creature can't be blocked this turn.| Waterbending Lesson|Avatar: The Last Airbender|80|C|{3}{U}|Sorcery - Lesson|||Draw three cards. Then discard a card unless you waterbend {2}.| +Waterbending Scroll|Avatar: The Last Airbender|81|U|{1}{U}|Artifact|||{6}, {T}: Draw a card. This ability costs {1} less to activate for each Island you control.| Watery Grasp|Avatar: The Last Airbender|82|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature doesn't untap during its controller's untap step.$Waterbend {5}: Enchanted creature's owner shuffles it into their library.| Yue, the Moon Spirit|Avatar: The Last Airbender|83|R|{3}{U}|Legendary Creature - Spirit Ally|3|3|Flying, vigilance$Waterbend {5}, {T}: You may cast a noncreature spell from your hand without paying its mana cost.| Azula Always Lies|Avatar: The Last Airbender|84|C|{1}{B}|Instant - Lesson|||Choose one or both --$* Target creature gets -1/-1 until end of turn.$* Put a +1/+1 counter on target creature.| +Azula, On the Hunt|Avatar: The Last Airbender|85|U|{3}{B}|Legendary Creature - Human Noble|4|3|Firebending 2$Whenever Azula attacks, you lose 1 life and create a Clue token.| Beetle-Headed Merchants|Avatar: The Last Airbender|86|C|{4}{B}|Creature - Human Citizen|5|4|Whenever this creature attacks, you may sacrifice another creature or artifact. If you do, draw a card and put a +1/+1 counter on this creature.| +Boiling Rock Rioter|Avatar: The Last Airbender|87|R|{2}{B}|Creature - Human Rogue Ally|3|3|Firebending 1$Tap an untapped Ally you control: Exile target card from a graveyard.$Whenever this creature attacks, you may cast an Ally spell from among cards you own exiled with this creature.| Buzzard-Wasp Colony|Avatar: The Last Airbender|88|U|{3}{B}|Creature - Bird Insect|2|2|Flying$When this creature enters, you may sacrifice an artifact or creature. If you do, draw a card.$Whenever another creature you control dies, if it had counters on it, put its counters on this creature.| +Callous Inspector|Avatar: The Last Airbender|89|C|{B}|Creature - Human Soldier|1|1|Menace$When this creature dies, it deals 1 damage to you. Create a Clue token.| +Canyon Crawler|Avatar: The Last Airbender|90|C|{4}{B}{B}|Creature - Spider Beast|6|6|Deathtouch$When this creature enters, create a Food token.$Swampcycling {2}| Cat-Gator|Avatar: The Last Airbender|91|U|{6}{B}|Creature - Fish Crocodile|3|2|Lifelink$When this creature enters, it deals damage equal to the number of Swamps you control to any target.| Corrupt Court Official|Avatar: The Last Airbender|92|C|{1}{B}|Creature - Human Advisor|1|1|When this creature enters, target opponent discards a card.| Dai Li Indoctrination|Avatar: The Last Airbender|93|C|{1}{B}|Sorcery - Lesson|||Choose one --$* Target opponent reveals their hand. You choose a nonland permanent card from it. That player discards that card.$* Earthbend 2.| +Day of Black Sun|Avatar: The Last Airbender|94|R|{X}{B}{B}|Sorcery|||Each creature with mana value X or less loses all abilities until end of turn. Destroy those creatures.| +Deadly Precision|Avatar: The Last Airbender|95|C|{B}|Sorcery|||As an additional cost to cast this spell, pay {4} or sacrifice an artifact or creature.$Destroy target creature.| Epic Downfall|Avatar: The Last Airbender|96|U|{1}{B}|Sorcery|||Exile target creature with mana value 3 or greater.| +Fatal Fissure|Avatar: The Last Airbender|97|U|{1}{B}|Instant|||Choose target creature. When that creature dies this turn, you earthbend 4.| +The Fire Nation Drill|Avatar: The Last Airbender|98|R|{2}{B}{B}|Legendary Artifact - Vehicle|6|3|Trample$When The Fire Nation Drill enters, you may tap it. When you do, destroy target creature with power 4 or less.${1}: Permanents your opponents control lose hexproof and indestructible until end of turn.$Crew 2| Fire Nation Engineer|Avatar: The Last Airbender|99|U|{2}{B}|Creature - Human Artificer|2|3|Raid -- At the beginning of your end step, if you attacked this turn, put a +1/+1 counter on another target creature or Vehicle you control.| +Fire Navy Trebuchet|Avatar: The Last Airbender|100|U|{2}{B}|Artifact Creature - Wall|0|4|Defender, reach$Whenever you attack, create a 2/1 colorless Construct artifact creature token with flying named Ballistic Boulder that's tapped and attacking. Sacrifice that token at the beginning of the next end step.| +Foggy Swamp Hunters|Avatar: The Last Airbender|101|C|{3}{B}|Creature - Human Ranger Ally|3|4|As long as you've drawn two or more cards this turn, this creature has lifelink and menace.| +Foggy Swamp Visions|Avatar: The Last Airbender|102|R|{1}{B}{B}|Sorcery|||As an additional cost to cast this spell, waterbend {X}.$Exile X target creature cards from graveyards. For each creature card exiled this way, create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens.| Heartless Act|Avatar: The Last Airbender|103|U|{1}{B}|Instant|||Choose one --$* Destroy target creature with no counters on it.$* Remove up to three counters from target creature.| Hog-Monkey|Avatar: The Last Airbender|104|C|{2}{B}|Creature - Boar Monkey|3|2|At the beginning of combat on your turn, target creature you control with a +1/+1 counter on it gains menace until end of turn.$Exhaust -- {5}: Put two +1/+1 counters on this creature.| +Joo Dee, One of Many|Avatar: The Last Airbender|105|U|{1}{B}|Creature - Human Advisor|2|2|{B}, {T}: Surveil 1. Create a token that's a copy of this creature, then sacrifice an artifact or creature. Activate only as a sorcery.| +June, Bounty Hunter|Avatar: The Last Airbender|106|U|{1}{B}|Legendary Creature - Human Mercenary|2|2|June can't be blocked as long as you've drawn two or more cards this turn.${1}, Sacrifice another creature: Create a Clue token. Activate only during your turn.| +Koh, the Face Stealer|Avatar: The Last Airbender|107|M|{4}{B}{B}|Legendary Creature - Shapeshifter Spirit|6|6|When Koh enters, exile up to one other target creature.$Whenever another nontoken creature dies, you may exile it.$Pay 1 life: Choose a creature card exiled with Koh.$Koh has all activated and triggered abilities of the last chosen card.| +Lo and Li, Twin Tutors|Avatar: The Last Airbender|108|U|{4}{B}|Legendary Creature - Human Advisor|2|2|When Lo and Li enter, search your library for a Lesson or Noble card, reveal it, put it into your hand, then shuffle.$Noble creatures you control and Lesson spells you control have lifelink.| +Mai, Scornful Striker|Avatar: The Last Airbender|109|R|{1}{B}|Legendary Creature - Human Noble Ally|2|2|First strike$Whenever a player casts a noncreature spell, they lose 2 life.| Merchant of Many Hats|Avatar: The Last Airbender|110|C|{1}{B}|Creature - Human Peasant Ally|2|2|{2}{B}: Return this card from your graveyard to your hand.| +Northern Air Temple|Avatar: The Last Airbender|111|U|{B}|Legendary Enchantment - Shrine|||When Northern Air Temple enters, each opponent loses X life and you gain X life, where X is the number of Shrines you control.$Whenever another Shrine you control enters, each opponent loses 1 life and you gain 1 life.| +Obsessive Pursuit|Avatar: The Last Airbender|112|R|{1}{B}|Enchantment|||When this enchantment enters and at the beginning of your upkeep, you lose 1 life and create a Clue token.$Whenever you attack, put X +1/+1 counters on target attacking creature, where X is the number of permanents you've sacrificed this turn. If X is three or greater, that creature gains lifelink until end of turn.| Ozai's Cruelty|Avatar: The Last Airbender|113|U|{2}{B}|Sorcery - Lesson|||Ozai's Cruelty deals 2 damage to target player. That player discards two cards.| +Phoenix Fleet Airship|Avatar: The Last Airbender|114|M|{2}{B}{B}|Artifact - Vehicle|4|4|Flying$At the beginning of your end step, if you sacrificed a permanent this turn, create a token that's a copy of this Vehicle.$As long as you control eight or more permanents named Phoenix Fleet Airship, this Vehicle is an artifact creature.$Crew 1| +Pirate Peddlers|Avatar: The Last Airbender|115|C|{2}{B}|Creature - Human Pirate|2|2|Deathtouch$Whenever you sacrifice another permanent, put a +1/+1 counter on this creature.| +Raven Eagle|Avatar: The Last Airbender|116|R|{2}{B}|Creature - Bird Assassin|2|3|Flying$Whenever this creature enters or attacks, exile up to one target card from a graveyard. If a creature card is exiled this way, create a Clue token.$Whenever you draw your second card each turn, each opponent loses 1 life and you gain 1 life.| The Rise of Sozin|Avatar: The Last Airbender|117|M|{4}{B}{B}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I -- Destroy all creatures.$II -- Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. Then that player shuffles.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| Fire Lord Sozin|Avatar: The Last Airbender|117|M||Legendary Creature - Human Noble|5|5|Menace, firebending 3$Whenever Fire Lord Sozin deals combat damage to a player, you may pay {X}. When you do, put any number of target creature cards with total mana value X or less from that player's graveyard onto the battlefield under your control.| +Ruinous Waterbending|Avatar: The Last Airbender|118|U|{1}{B}{B}|Sorcery - Lesson|||As an additional cost to cast this spell, you may waterbend {4}.$All creatures get -2/-2 until end of turn. If this spell's additional cost was paid, whenever a creature dies this turn, you gain 1 life.| +Sold Out|Avatar: The Last Airbender|119|C|{3}{B}|Instant|||Exile target creature. If it was dealt damage this turn, create a Clue token.| +Swampsnare Trap|Avatar: The Last Airbender|120|C|{2}{B}|Enchantment - Aura|||This spell costs {1} less to cast if it targets a creature with flying.$Enchant creature$Enchanted creature gets -5/-3.| +Tundra Tank|Avatar: The Last Airbender|121|U|{2}{B}|Artifact - Vehicle|4|4|Firebending 1$When this Vehicle enters, target creature you control gains indestructible until end of turn.$Crew 1| +Wolfbat|Avatar: The Last Airbender|122|U|{2}{B}|Creature - Wolf Bat|2|2|Flying$Whenever you draw your second card each turn, you may pay {B}. If you do, return this card from your graveyard to the battlefield with a finality counter on it.| +Zuko's Conviction|Avatar: The Last Airbender|123|U|{B}|Instant|||Kicker {4}$Return target creature card from your graveyard to your hand. If this spell was kicked, instead put that card onto the battlefield tapped.| +Boar-q-pine|Avatar: The Last Airbender|124|C|{2}{R}|Creature - Boar Porcupine|2|2|Whenever you cast a noncreature spell, put a +1/+1 counter on this creature.| +Bumi Bash|Avatar: The Last Airbender|125|C|{3}{R}|Sorcery|||Choose one --$* Bumi Bash deals damage equal to the number of lands you control to target creature.$* Destroy target land creature or nonbasic land.| +The Cave of Two Lovers|Avatar: The Last Airbender|126|U|{3}{R}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create two 1/1 white Ally creature tokens.$II -- Search your library for a Mountain or Cave card, reveal it, put it into your hand,$then shuffle.$III -- Earthbend 3.| +Combustion Man|Avatar: The Last Airbender|127|U|{3}{R}{R}|Legendary Creature - Human Assassin|4|6|Whenever Combustion Man attacks, destroy target permanent unless its controller has Combustion Man deal damage to them equal to his power.| +Combustion Technique|Avatar: The Last Airbender|128|U|{1}{R}|Instant - Lesson|||Combustion Technique deals damage equal to 2 plus the number of Lesson cards in your graveyard to target creature. If that creature would die this turn, exile it instead.| +Crescent Island Temple|Avatar: The Last Airbender|129|U|{3}{R}|Legendary Enchantment - Shrine|||When Crescent Island Temple enters, for each Shrine you control, create a 1/1 red Monk creature token with prowess.$Whenever another Shrine you control enters, create a 1/1 red Monk creature token with prowess.| +Cunning Maneuver|Avatar: The Last Airbender|130|C|{1}{R}|Instant|||Target creature gets +3/+1 until end of turn.$Create a Clue token.| Deserter's Disciple|Avatar: The Last Airbender|131|C|{1}{R}|Creature - Human Rebel Ally|2|2|{T}: Another target creature you control with power 2 or less can't be blocked this turn.| Fated Firepower|Avatar: The Last Airbender|132|M|{X}{R}{R}{R}|Enchantment|||Flash$This enchantment enters with X fire counters on it.$If a source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus an amount of damage equal to the number of fire counters on this enchantment instead.| Fire Nation Attacks|Avatar: The Last Airbender|133|U|{4}{R}|Instant|||Create two 2/2 red Soldier creature tokens with firebending 1.$Flashback {8}{R}| +Fire Nation Cadets|Avatar: The Last Airbender|134|C|{R}|Creature - Human Soldier|1|2|This creature has firebending 2 as long as there's a Lesson card in your graveyard.${2}: This creature gets +1/+0 until end of turn.| +Fire Nation Raider|Avatar: The Last Airbender|135|C|{3}{R}|Creature - Human Soldier|4|2|Raid -- When this creature enters, if you attacked this turn, create a Clue token.| Fire Sages|Avatar: The Last Airbender|136|U|{1}{R}|Creature - Human Cleric|2|2|Firebending 1${1}{R}{R}: Put a +1/+1 counter on this creature.| +Firebender Ascension|Avatar: The Last Airbender|137|R|{1}{R}|Enchantment|||When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1.$Whenever a creature you control attacking causes a triggered ability of that creature to trigger, put a quest counter on this enchantment. Then if it has four or more quest counters on it, you may copy that ability. You may choose new targets for the copy.| +Firebending Lesson|Avatar: The Last Airbender|138|C|{R}|Instant - Lesson|||Kicker {4}$Firebending Lesson deals 2 damage to target creature. If this spell was kicked, it deals 5 damage to that creature instead.| +Firebending Student|Avatar: The Last Airbender|139|R|{1}{R}|Creature - Human Monk|1|2|Prowess$Firebending X, where X is this creature's power.| How to Start a Riot|Avatar: The Last Airbender|140|C|{2}{R}|Instant - Lesson|||Target creature gains menace until end of turn.$Creatures target player controls get +2/+0 until end of turn.| +Iroh's Demonstration|Avatar: The Last Airbender|141|U|{1}{R}|Sorcery - Lesson|||Choose one --$* Iroh's Demonstration deals 1 damage to each creature your opponents control.$* Iroh's Demonstration deals 4 damage to target creature.| +Jeong Jeong, the Deserter|Avatar: The Last Airbender|142|U|{2}{R}|Legendary Creature - Human Rebel Ally|2|3|Firebending 1$Exhaust -- {3}: Put a +1/+1 counter on Jeong Jeong. When you next cast a Lesson spell this turn, copy it and you may choose new targets for the copy.| +Jet's Brainwashing|Avatar: The Last Airbender|143|U|{R}|Sorcery|||Kicker {3}$Target creature can't block this turn. If this spell was kicked, gain control of that creature until end of turn, untap it, and it gains haste until end of turn.$Create a Clue token.| +The Last Agni Kai|Avatar: The Last Airbender|144|R|{1}{R}|Instant|||Target creature you control fights target creature an opponent controls. If the creature the opponent controls is dealt excess damage this way, add that much {R}.$Until end of turn, you don't lose unspent red mana as steps and phases end.| +The Legend of Roku|Avatar: The Last Airbender|145|M|{2}{R}{R}|Enchantment - Saga|||(As this Saga enters and after your draw$step, add a lore counter.)$I -- Exile the top three cards of your library. Until the end of your next turn, you may play those cards.$II -- Add one mana of any color.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Roku|Avatar: The Last Airbender|145|M||Legendary Creature - Avatar|4|4|Firebending 4${8}: Create a 4/4 red Dragon creature token with flying and firebending 4.| Lightning Strike|Avatar: The Last Airbender|146|C|{1}{R}|Instant|||Lightning Strike deals 3 damage to any target.| +Mai, Jaded Edge|Avatar: The Last Airbender|147|U|{1}{R}|Legendary Creature - Human Noble|1|3|Prowess$Exhaust -- {3}: Put a double strike counter on Mai.| Mongoose Lizard|Avatar: The Last Airbender|148|C|{4}{R}{R}|Creature - Mongoose Lizard|5|6|Menace$When this creature enters, it deals 1 damage to any target.$Mountaincycling {2}| +Price of Freedom|Avatar: The Last Airbender|149|U|{1}{R}|Sorcery - Lesson|||Destroy target artifact or land an opponent controls. Its controller may search their library for a basic land card, put it onto the battlefield tapped, then shuffle.$Draw a card.| +Ran and Shaw|Avatar: The Last Airbender|150|R|{3}{R}{R}|Legendary Creature - Dragon|4|4|Flying, firebending 2$When Ran and Shaw enter, if you cast them and there are three or more Dragon and/or Lesson cards in your graveyard, create a token that's a copy of Ran and Shaw, except it's not legendary.${3}{R}: Dragons you control get +2/+0 until end of turn.| Redirect Lightning|Avatar: The Last Airbender|151|R|{R}|Instant - Lesson|||As an additional cost to cast this spell, pay 5 life or pay {2}.$Change the target of target spell or ability with a single target.| Rough Rhino Cavalry|Avatar: The Last Airbender|152|C|{4}{R}|Creature - Human Mercenary|5|5|Firebending 2$Exhaust -- {8}: Put two +1/+1 counters on this creature. It gains trample until end of turn.| +Solstice Revelations|Avatar: The Last Airbender|153|U|{2}{R}|Instant - Lesson|||Exile cards from the top of your library until you exile a nonland card. You may cast that card without paying its mana cost if the spell's mana value is less than the number of Mountains you control. If you don't cast that card this way, put it into your hand.$Flashback {6}{R}| +Sozin's Comet|Avatar: The Last Airbender|154|M|{3}{R}{R}|Sorcery|||Each creature you control gains firebending 5 until end of turn.$Foretell {2}{R}| +Tiger-Dillo|Avatar: The Last Airbender|155|U|{1}{R}|Creature - Cat Armadillo|4|3|This creature can't attack or block unless you control another creature with power 4 or greater.| +Treetop Freedom Fighters|Avatar: The Last Airbender|156|C|{2}{R}|Creature - Human Rebel Ally|2|1|Haste$When this creature enters, create a 1/1 white Ally creature token.| +Twin Blades|Avatar: The Last Airbender|157|U|{2}{R}|Artifact - Equipment|||Flash$When this Equipment enters, attach it to target creature you control. That creature gains double strike until end of turn.$Equipped creature gets +1/+1.$Equip {2}| +Ty Lee, Artful Acrobat|Avatar: The Last Airbender|158|U|{2}{R}|Legendary Creature - Human Performer|3|2|Prowess$Whenever Ty Lee attacks, you may pay {1}. When you do, target creature can't block this turn.| +War Balloon|Avatar: The Last Airbender|159|U|{2}{R}|Artifact - Vehicle|4|3|Flying${1}: Put a fire counter on this Vehicle.$As long as this Vehicle has three or more fire counters on it, it's an artifact creature.$Crew 3| +Wartime Protestors|Avatar: The Last Airbender|160|R|{3}{R}|Creature - Human Rebel Ally|4|4|Haste$Whenever another Ally you control enters, put a +1/+1 counter on that creature and it gains haste until end of turn.| Yuyan Archers|Avatar: The Last Airbender|161|C|{1}{R}|Creature - Human Archer|3|1|Reach$When this creature enters, you may discard a card. If you do, draw a card.| +Zhao, the Moon Slayer|Avatar: The Last Airbender|162|R|{1}{R}|Legendary Creature - Human Soldier|2|2|Menace$Nonbasic lands enter tapped.${7}: Put a conqueror counter on Zhao.$As long as Zhao has a conqueror counter on him, nonbasic lands are Mountains.| Zuko, Exiled Prince|Avatar: The Last Airbender|163|U|{3}{R}|Legendary Creature - Human Noble|4|3|Firebending 3${3}: Exile the top card of your library. You may play that card this turn.| +Allies at Last|Avatar: The Last Airbender|164|U|{2}{G}|Instant|||Affinity for Allies$Up to two target creatures you control each deal damage equal to their power to target creature an opponent controls.| +Avatar Destiny|Avatar: The Last Airbender|165|R|{2}{G}{G}|Enchantment - Aura|||Enchant creature you control$Enchanted creature gets +1/+1 for each creature card in your graveyard and is an Avatar in addition to its other types.$When enchanted creature dies, mill cards equal to its power. Return this card to its owner's hand and up to one creature card milled this way to the battlefield under your control.| Badgermole|Avatar: The Last Airbender|166|C|{4}{G}|Creature - Badger Mole|4|4|When this creature enters, earthbend 2.$Creatures you control with +1/+1 counters on them have trample.| +Badgermole Cub|Avatar: The Last Airbender|167|M|{1}{G}|Creature - Badger Mole|2|2|When this creature enters, earthbend 1.$Whenever you tap a creature for mana, add an additional {G}.| +The Boulder, Ready to Rumble|Avatar: The Last Airbender|168|U|{3}{G}|Legendary Creature - Human Warrior Performer|4|4|Whenever The Boulder attacks, earthbend X, where X is the number of creatures you control with power 4 or greater.| +Bumi, King of Three Trials|Avatar: The Last Airbender|169|U|{5}{G}|Legendary Creature - Human Noble Ally|4|4|When Bumi enters, choose up to X, where X is the number of Lesson cards in your graveyard --$* Put three +1/+1 counters on Bumi.$* Target player scries 3.$* Earthbend 3.| +Cycle of Renewal|Avatar: The Last Airbender|170|C|{2}{G}|Instant - Lesson|||Sacrifice a land. Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.| +Diligent Zookeeper|Avatar: The Last Airbender|171|R|{3}{G}|Creature - Human Citizen Ally|4|4|Each non-Human creature you control gets +1/+1 for each of its creature types, to a maximum of 10.| +The Earth King|Avatar: The Last Airbender|172|R|{3}{G}|Legendary Creature - Human Noble Ally|2|2|When The Earth King enters, create a 4/4 green Bear creature token.$Whenever one or more creatures you control with power 4 or greater attack, search your library for up to that many basic land cards, put them onto the battlefield tapped, then shuffle.| +Earth Kingdom General|Avatar: The Last Airbender|173|U|{3}{G}|Creature - Human Soldier Ally|2|2|When this creature enters, earthbend 2.$Whenever you put one or more +1/+1 counters on a creature, you may gain that much life. Do this only once each turn.| Earth Rumble|Avatar: The Last Airbender|174|U|{3}{G}|Sorcery|||Earthbend 2. When you do, up to one target creature you control fights target creature an opponent controls.| +Earthbender Ascension|Avatar: The Last Airbender|175|R|{2}{G}|Enchantment|||When this enchantment enters, earthbend 2. Then search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Landfall -- Whenever a land you control enters, put a quest counter on this enchantment. When you do, if it has four or more quest counters on it, put a +1/+1 counter on target creature you control. It gains trample until end of turn.| Earthbending Lesson|Avatar: The Last Airbender|176|C|{3}{G}|Sorcery - Lesson|||Earthbend 4.| +Earthen Ally|Avatar: The Last Airbender|177|R|{G}|Creature - Human Soldier Ally|0|2|This creature gets +1/+0 for each color among Allies you control.${2}{W}{U}{B}{R}{G}: Earthbend 5.| +Elemental Teachings|Avatar: The Last Airbender|178|R|{4}{G}|Instant - Lesson|||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 onto the battlefield tapped, then shuffle.| Flopsie, Bumi's Buddy|Avatar: The Last Airbender|179|U|{4}{G}{G}|Legendary Creature - Ape Goat|4|4|When Flopsie enters, put a +1/+1 counter on each creature you control.$Each creature you control with power 4 or greater can't be blocked by more than one creature.| +Foggy Swamp Vinebender|Avatar: The Last Airbender|180|C|{3}{G}|Creature - Human Plant Ally|4|3|This creature can't be blocked by creatures with power 2 or less.$Waterbend {5}: Put a +1/+1 counter on this creature. Activate only during your turn.| +Great Divide Guide|Avatar: The Last Airbender|181|R|{1}{G}|Creature - Human Scout Ally|2|3|Each land and Ally you control has "{T}: Add one mana of any color."| Haru, Hidden Talent|Avatar: The Last Airbender|182|U|{1}{G}|Legendary Creature - Human Peasant Ally|1|1|Whenever another Ally you control enters, earthbend 1.| +Invasion Tactics|Avatar: The Last Airbender|183|U|{4}{G}|Enchantment|||When this enchantment enters, creatures you control get +2/+2 until end of turn.$Whenever one or more Allies you control deal combat damage to a player, draw a card.| +Kyoshi Island Plaza|Avatar: The Last Airbender|184|U|{3}{G}|Legendary Enchantment - Shrine|||When Kyoshi Island Plaza enters, search your library for up to X basic land cards, where X is the number of Shrines you control. Put those cards onto the battlefield tapped, then shuffle.$Whenever another Shrine you control enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| +Leaves from the Vine|Avatar: The Last Airbender|185|U|{1}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Mill three cards, then create a Food token.$II -- Put a +1/+1 counter on each of up to two target creatures you control.$III -- Draw a card if there's a creature or Lesson card in your graveyard.| +The Legend of Kyoshi|Avatar: The Last Airbender|186|M|{4}{G}{G}|Enchantment - Saga|||(As this Saga enters and after your draw$step, add a lore counter.)$I -- Draw cards equal to the greatest power among creatures you control.$II -- Earthbend X, where X is the number of cards in your hand. That land becomes an Island in addition to its other types.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Kyoshi|Avatar: The Last Airbender|186|M||Legendary Creature - Avatar|5|4|Lands you control have trample and hexproof.${T}: Add X mana of any one color, where X is the greatest power among creatures you control.| +Origin of Metalbending|Avatar: The Last Airbender|187|C|{1}{G}|Instant - Lesson|||Choose one --$* Destroy target artifact or enchantment.$* Put a +1/+1 counter on target creature you control. It gains indestructible until end of turn.| Ostrich-Horse|Avatar: The Last Airbender|188|C|{2}{G}|Creature - Bird Horse|3|1|When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature.| Pillar Launch|Avatar: The Last Airbender|189|C|{G}|Instant|||Target creature gets +2/+2 and gains reach until end of turn. Untap it.| Raucous Audience|Avatar: The Last Airbender|190|C|{1}{G}|Creature - Human Citizen|2|1|{T}: Add {G}. If you control a creature with power 4 or greater, add {G}{G} instead.| Rebellious Captives|Avatar: The Last Airbender|191|C|{1}{G}|Creature - Human Peasant Ally|2|2|Exhaust -- {6}: Put two +1/+1 counters on this creature, then earthbend 2.| +Rockalanche|Avatar: The Last Airbender|192|U|{2}{G}|Sorcery - Lesson|||Earthbend X, where X is the number of Forests you control.$Flashback {5}{G}| Rocky Rebuke|Avatar: The Last Airbender|193|C|{1}{G}|Instant|||Target creature you control deals damage equal to its power to target creature an opponent controls.| Saber-Tooth Moose-Lion|Avatar: The Last Airbender|194|C|{4}{G}{G}|Creature - Elk Cat|7|7|Reach$Forestcycling {2}| +Seismic Sense|Avatar: The Last Airbender|195|U|{G}|Sorcery - Lesson|||Look at the top X cards of your library, where X is the number of lands you control. 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.| +Shared Roots|Avatar: The Last Airbender|196|U|{1}{G}|Sorcery - Lesson|||Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.| +Sparring Dummy|Avatar: The Last Airbender|197|U|{1}{G}|Artifact Creature - Scarecrow|1|3|Defender${T}: Mill a card. You may put a land card milled this way into your hand. You gain 2 life if a Lesson card is milled this way.| Toph, the Blind Bandit|Avatar: The Last Airbender|198|U|{2}{G}|Legendary Creature - Human Warrior Ally|*|3|When Toph enters, earthbend 2.$Toph's power is equal to the number of +1/+1 counters on lands you control.| +True Ancestry|Avatar: The Last Airbender|199|U|{1}{G}|Sorcery - Lesson|||Return up to one target permanent card from your graveyard to your hand.$Create a Clue token.| Turtle-Duck|Avatar: The Last Airbender|200|C|{G}|Creature - Turtle Bird|0|4|{3}: Until end of turn, this creature has base power 4 and gains trample.| +Unlucky Cabbage Merchant|Avatar: The Last Airbender|201|U|{1}{G}|Creature - Human Citizen|2|2|When this creature enters, create a Food token.$Whenever you sacrifice a Food, you may search your library for a basic land card and put it onto the battlefield tapped. If you search your library this way, put this creature on the bottom of its owner's library, then shuffle.| +Walltop Sentries|Avatar: The Last Airbender|202|C|{2}{G}|Creature - Human Soldier Ally|2|3|Reach, deathtouch$When this creature dies, if there's a Lesson card in your graveyard, you gain 2 life.| +Aang, at the Crossroads|Avatar: The Last Airbender|203|R|{2}{G}{W}{U}|Legendary Creature - Human Avatar Ally|3|3|Flying$When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.$When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep.| +Aang, Destined Savior|Avatar: The Last Airbender|203|R||Legendary Creature - Avatar Ally|4|4|Flying$Land creatures you control have vigilance.$At the beginning of combat on your turn, earthbend 2.| +Aang, Swift Savior|Avatar: The Last Airbender|204|R|{1}{W}{U}|Legendary Creature - Human Avatar Ally|2|3|Flash$Flying$When Aang enters, airbend up to one other target creature or spell.$Waterbend {8}: Transform Aang.| +Aang and La, Ocean's Fury|Avatar: The Last Airbender|204|R||Legendary Creature - Avatar Spirit Ally|5|5|Reach, trample$Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control.| Abandon Attachments|Avatar: The Last Airbender|205|C|{1}{U/R}|Instant - Lesson|||You may discard a card. If you do, draw two cards.| +Air Nomad Legacy|Avatar: The Last Airbender|206|U|{W}{U}|Enchantment|||When this enchantment enters, create a Clue token.$Creatures you control with flying get +1/+1.| Avatar Aang|Avatar: The Last Airbender|207|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| Aang, Master of Elements|Avatar: The Last Airbender|207|M||Legendary Creature - Avatar Ally|6|6|Flying$Spells you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| +Azula, Cunning Usurper|Avatar: The Last Airbender|208|R|{2}{U}{B}{B}|Legendary Creature - Human Noble Rogue|4|4|Firebending 2$When Azula enters, target opponent exiles a nontoken creature they control, then they exile a nonland card from their graveyard.$During your turn, you may cast cards exiled with Azula and you may cast them as though they had flash. Mana of any type can be spent to cast those spells.| +Beifong's Bounty Hunters|Avatar: The Last Airbender|209|R|{2}{B}{G}|Creature - Human Mercenary|4|4|Whenever a nonland creature you control dies, earthbend X, where X is that creature's power.| +Bitter Work|Avatar: The Last Airbender|210|U|{1}{R}{G}|Enchantment|||Whenever you attack a player with one or more creatures with power 4 or greater, draw a card.$Exhaust -- {4}: Earthbend 4. Activate only during your turn.| +Bumi, Unleashed|Avatar: The Last Airbender|211|M|{3}{R}{G}|Legendary Creature - Human Noble Ally|5|4|Trample$When Bumi enters, earthbend 4.$Whenever Bumi deals combat damage to a player, untap all lands you control. After this phase, there is an additional combat phase. Only land creatures can attack during that combat phase.| Cat-Owl|Avatar: The Last Airbender|212|C|{3}{W/U}|Creature - Cat Bird|3|3|Flying$Whenever this creature attacks, untap target artifact or creature.| +Cruel Administrator|Avatar: The Last Airbender|213|U|{3}{B}{R}|Creature - Human Soldier|5|4|Raid -- This creature enters with a +1/+1 counter on it if you attacked this turn.$Whenever this creature attacks, create a 2/2 red Soldier creature token with firebending 1.| +Dai Li Agents|Avatar: The Last Airbender|214|U|{3}{B}{G}|Creature - Human Soldier|3|4|When this creature enters, earthbend 1, then earthbend 1.$Whenever this creature attacks, each opponent loses X life and you gain X life, where X is the number of creatures you control with +1/+1 counters on them.| +Dragonfly Swarm|Avatar: The Last Airbender|215|U|{1}{U}{R}|Creature - Dragon Insect|*|3|Flying, ward {1}$This creature's power is equal to the number of noncreature, nonland cards in your graveyard.$When this creature dies, if there's a Lesson card in your graveyard, draw a card.| Earth Kingdom Soldier|Avatar: The Last Airbender|216|C|{4}{G/W}|Creature - Human Soldier|3|4|Vigilance$When this creature enters, put a +1/+1 counter on each of up to two target creatures you control.| +Earth King's Lieutenant|Avatar: The Last Airbender|217|R|{G}{W}|Creature - Human Soldier Ally|1|1|Trample$When this creature enters, put a +1/+1 counter on each other Ally creature you control.$Whenever another Ally you control enters, put a +1/+1 counter on this creature.| +Earth Rumble Wrestlers|Avatar: The Last Airbender|218|C|{3}{R/G}|Creature - Human Warrior Performer|3|4|Reach$This creature gets +1/+0 and has trample as long as you control a land creature or a land entered the battlefield under your control this turn.| Earth Village Ruffians|Avatar: The Last Airbender|219|C|{2}{B/G}|Creature - Human Soldier Rogue|3|1|When this creature dies, earthbend 2.| +Fire Lord Azula|Avatar: The Last Airbender|220|R|{1}{U}{B}{R}|Legendary Creature - Human Noble|4|4|Firebending 2$Whenever you cast a spell while Fire Lord Azula is attacking, copy that spell. You may choose new targets for the copy.| Fire Lord Zuko|Avatar: The Last Airbender|221|R|{R}{W}{B}|Legendary Creature - Human Noble Ally|2|4|Firebending X, where X is Fire Lord Zuko's power.$Whenever you cast a spell from exile and whenever a permanent you control enters from exile, put a +1/+1 counter on each creature you control.| +Foggy Swamp Spirit Keeper|Avatar: The Last Airbender|222|U|{1}{U}{B}|Creature - Human Druid Ally|2|4|Lifelink$Whenever you draw your second card each turn, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."| +Guru Pathik|Avatar: The Last Airbender|223|U|{2}{G/U}{G/U}|Legendary Creature - Human Monk Ally|2|4|When Guru Pathik enters, look at the top five cards of your library. You may reveal a Lesson, Saga, or Shrine card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.$Whenever you cast a Lesson, Saga, or Shrine spell, put a +1/+1 counter on another target creature you control.| +Hama, the Bloodbender|Avatar: The Last Airbender|224|U|{2}{U/B}{U/B}{U/B}|Legendary Creature - Human Warlock|3|3|When Hama enters, target opponent mills three cards. Exile up to one noncreature, nonland card from that player's graveyard. For as long as you control Hama, you may cast the exiled card during your turn by waterbending {X} rather than paying its mana cost, where X is its mana value.| Hei Bai, Spirit of Balance|Avatar: The Last Airbender|225|U|{2}{W/B}{W/B}|Legendary Creature - Bear Spirit|3|3|Whenever Hei Bai enters or attacks, you may sacrifice another creature or artifact. If you do, put two +1/+1 counters on Hei Bai.$When Hei Bai leaves the battlefield, put its counters on target creature you control.| +Hermitic Herbalist|Avatar: The Last Airbender|226|U|{G}{U}|Creature - Human Druid Ally|2|3|{T}: Add one mana of any color.${T}: Add two mana in any combination of colors. Spend this mana only to cast Lesson spells.| +Iroh, Grand Lotus|Avatar: The Last Airbender|227|R|{3}{G}{U}{R}|Legendary Creature - Human Noble Ally|5|5|Firebending 2$During your turn, each non-Lesson instant and sorcery card in your graveyard has flashback. The flashback cost is equal to that card's mana cost.$During your turn, each Lesson card in your graveyard has flashback {1}.| +Iroh, Tea Master|Avatar: The Last Airbender|228|R|{1}{R}{W}|Legendary Creature - Human Citizen Ally|2|2|When Iroh enters, create a Food token.$At the beginning of combat on your turn, you may have target opponent gain control of target permanent you control. When you do, create a 1/1 white Ally creature token. Put a +1/+1 counter on that token for each permanent you own that your opponents control.| +Jet, Freedom Fighter|Avatar: The Last Airbender|229|U|{2}{R/W}{R/W}{R/W}|Legendary Creature - Human Rebel Ally|3|1|When Jet enters, he deals damage equal to the number of creatures you control to target creature an opponent controls.$When Jet dies, put a +1/+1 counter on each of up to two target creatures.| Katara, the Fearless|Avatar: The Last Airbender|230|R|{G}{W}{U}|Legendary Creature - Human Warrior Ally|3|3|If a triggered ability of an Ally you control triggers, that ability triggers an additional time.| Katara, Water Tribe's Hope|Avatar: The Last Airbender|231|R|{2}{W}{U}{U}|Legendary Creature - Human Warrior Ally|3|3|Vigilance$When Katara enters, create a 1/1 white Ally creature token.$Waterbend {X}: Creatures you control have base power and toughness X/X until end of turn. X can't be 0. Activate only during your turn.| +The Lion-Turtle|Avatar: The Last Airbender|232|R|{1}{G}{U}|Legendary Creature - Elder Cat Turtle|3|6|Vigilance, reach$When The Lion-Turtle enters, you gain 3 life.$The Lion-Turtle can't attack or block unless there are three or more Lesson cards in your graveyard.${T}: Add one mana of any color.| Long Feng, Grand Secretariat|Avatar: The Last Airbender|233|U|{1}{B/G}{B/G}|Legendary Creature - Human Advisor|2|3|Whenever another creature you control or a land you control is put into a graveyard from the battlefield, put a +1/+1 counter on target creature you control.| +Messenger Hawk|Avatar: The Last Airbender|234|C|{2}{U/B}|Creature - Bird Scout|1|2|Flying$When this creature enters, create a Clue token.$This creature gets +2/+0 as long as you've drawn two or more cards this turn.| +Ozai, the Phoenix King|Avatar: The Last Airbender|235|M|{2}{B}{B}{R}{R}|Legendary Creature - Human Noble|7|7|Trample, firebending 4, haste$If you would lose unspent mana, that mana becomes red instead.$Ozai has flying and indestructible as long as you have six or more unspent mana.| +Platypus-Bear|Avatar: The Last Airbender|236|C|{1}{G/U}|Creature - Platypus Bear|2|3|Defender$When this creature enters, mill two cards.$As long as there is a Lesson card in your graveyard, this creature can attack as though it didn't have defender.| Pretending Poxbearers|Avatar: The Last Airbender|237|C|{1}{W/B}|Creature - Human Citizen Ally|2|1|When this creature dies, create a 1/1 white Ally creature token.| +Professor Zei, Anthropologist|Avatar: The Last Airbender|238|U|{U/R}{U/R}|Legendary Creature - Human Advisor Ally|0|3|{T}, Discard a card: Draw a card.${1}, {T}, Sacrifice Professor Zei: Return target instant or sorcery card from your graveyard to your hand. Activate only during your turn.| +Sandbender Scavengers|Avatar: The Last Airbender|239|R|{W}{B}|Creature - Human Rogue|1|1|Whenever you sacrifice another permanent, put a +1/+1 counter on this creature.$When this creature dies, you may exile it. When you do, return target creature card with mana value less than or equal to this creature's power from your graveyard to the battlefield.| Sokka, Bold Boomeranger|Avatar: The Last Airbender|240|R|{U}{R}|Legendary Creature - Human Warrior Ally|1|1|When Sokka enters, discard up to two cards, then draw that many cards.$Whenever you cast an artifact or Lesson spell, put a +1/+1 counter on Sokka.| Sokka, Lateral Strategist|Avatar: The Last Airbender|241|U|{1}{W/U}{W/U}|Legendary Creature - Human Warrior Ally|2|4|Vigilance$Whenever Sokka and at least one other creature attack, draw a card.| +Sokka, Tenacious Tactician|Avatar: The Last Airbender|242|R|{1}{U}{R}{W}|Legendary Creature - Human Warrior Ally|3|3|Menace, prowess$Other Allies you control have menace and prowess.$Whenever you cast a noncreature spell, create a 1/1 white Ally creature token.| Suki, Kyoshi Warrior|Avatar: The Last Airbender|243|U|{2}{G/W}{G/W}|Legendary Creature - Human Warrior Ally|*|4|Suki's power is equal to the number of creatures you control.$Whenever Suki attacks, create a 1/1 white Ally creature token that's tapped and attacking.| +Sun Warriors|Avatar: The Last Airbender|244|U|{2}{R}{W}|Creature - Human Warrior Ally|3|5|Firebending X, where X is the number of creatures you control.${5}: Create a 1/1 white Ally creature token.| +Tolls of War|Avatar: The Last Airbender|245|U|{W}{B}|Enchantment|||When this enchantment enters, create a Clue token.$Whenever you sacrifice a permanent during your turn, create a 1/1 white Ally creature token. This ability triggers only once each turn.| +Toph, Hardheaded Teacher|Avatar: The Last Airbender|246|R|{2}{R}{G}|Legendary Creature - Human Warrior Ally|3|4|When Toph enters, you may discard a card. If you do, return target instant or sorcery card from your graveyard to your hand.$Whenever you cast a spell, earthbend 1. If that spell is a Lesson, put an additional +1/+1 counter on that land.| Toph, the First Metalbender|Avatar: The Last Airbender|247|R|{1}{R}{G}{W}|Legendary Creature - Human Warrior Ally|3|3|Nontoken artifacts you control are lands in addition to their other types.$At the beginning of your end step, earthbend 2.| +Uncle Iroh|Avatar: The Last Airbender|248|U|{1}{R/G}{R/G}|Legendary Creature - Human Noble Ally|4|2|Firebending 1$Lesson spells you cast cost {1} less to cast.| Vindictive Warden|Avatar: The Last Airbender|249|C|{2}{B/R}|Creature - Human Soldier|2|3|Menace$Firebending 1${3}: This creature deals 1 damage to each opponent.| +Wandering Musicians|Avatar: The Last Airbender|250|C|{3}{R/W}|Creature - Human Bard Ally|2|5|Whenever this creature attacks, creatures you control get +1/+0 until end of turn.| +White Lotus Reinforcements|Avatar: The Last Airbender|251|U|{1}{G}{W}|Creature - Human Soldier Ally|2|3|Vigilance$Other Allies you control get +1/+1.| +Zhao, Ruthless Admiral|Avatar: The Last Airbender|252|U|{2}{B/R}{B/R}|Legendary Creature - Human Soldier|3|4|Firebending 2$Whenever you sacrifice another permanent, creatures you control get +1/+0 until end of turn.| +Zuko, Conflicted|Avatar: The Last Airbender|253|R|{B}{R}|Legendary Creature - Human Rogue|2|3|At the beginning of your first main phase, choose one that hasn't been chosen and you lose 2 life --$* Draw a card.$* Put a +1/+1 counter on Zuko.$* Add {R}.$* Exile Zuko, then return him to the battlefield under an opponent's control.| Barrels of Blasting Jelly|Avatar: The Last Airbender|254|C|{1}|Artifact|||{1}: Add one mana of any color. Activate only once each turn.${5}, {T}, Sacrifice this artifact: It deals 5 damage to target creature.| Bender's Waterskin|Avatar: The Last Airbender|255|C|{3}|Artifact|||Untap this artifact during each other player's untap step.${T}: Add one mana of any color.| +Fire Nation Warship|Avatar: The Last Airbender|256|U|{3}|Artifact - Vehicle|4|4|Reach$When this Vehicle dies, create a Clue token.$Crew 2| +Kyoshi Battle Fan|Avatar: The Last Airbender|257|C|{2}|Artifact - Equipment|||When this Equipment enters, create a 1/1 white Ally creature token, then attach this Equipment to it.$Equipped creature gets +1/+0.$Equip {2}| +Meteor Sword|Avatar: The Last Airbender|258|U|{7}|Artifact - Equipment|||When this Equipment enters, destroy target permanent.$Equipped creature gets +3/+3.$Equip {3}| +Planetarium of Wan Shi Tong|Avatar: The Last Airbender|259|M|{6}|Legendary Artifact|||{1}, {T}: Scry 2.$Whenever you scry or surveil, look at the top card of your library. You may cast that card without paying its mana cost. Do this only once each turn.| +Trusty Boomerang|Avatar: The Last Airbender|260|U|{1}|Artifact - Equipment|||Equipped creature has "{1}, {T}: Tap target creature. Return Trusty Boomerang to its owner's hand."$Equip {1}| +The Walls of Ba Sing Se|Avatar: The Last Airbender|261|M|{8}|Legendary Artifact Creature - Wall|0|30|Defender$Other permanents you control have indestructible.| +White Lotus Tile|Avatar: The Last Airbender|262|M|{4}|Artifact|||This artifact enters tapped.${T}: Add X mana of any one color, where X is the greatest number of creatures you control that have a creature type in common.| +Abandoned Air Temple|Avatar: The Last Airbender|263|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {W}.${3}{W}, {T}: Put a +1/+1 counter on each creature you control.| +Agna Qel'a|Avatar: The Last Airbender|264|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {U}.${2}{U}, {T}: Draw a card, then discard a card.| +Airship Engine Room|Avatar: The Last Airbender|265|C||Land|||This land enters tapped.${T}: Add {U} or {R}.${4}, {T}, Sacrifice this land: Draw a card.| +Ba Sing Se|Avatar: The Last Airbender|266|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {G}.${2}{G}, {T}: Earthbend 2. Activate only as a sorcery.| +Boiling Rock Prison|Avatar: The Last Airbender|267|C||Land|||This land enters tapped.${T}: Add {B} or {R}.${4}, {T}, Sacrifice this land: Draw a card.| +Fire Nation Palace|Avatar: The Last Airbender|268|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {R}.${1}{R}, {T}: Target creature you control gains firebending 4 until end of turn.| +Foggy Bottom Swamp|Avatar: The Last Airbender|269|C||Land|||This land enters tapped.${T}: Add {B} or {G}.${4}, {T}, Sacrifice this land: Draw a card.| +Jasmine Dragon Tea Shop|Avatar: The Last Airbender|270|R||Land|||{T}: Add {C}.${T}: Add one mana of any color. Spend this mana only to cast an Ally spell or activate an ability of an Ally source.${5}, {T}: Create a 1/1 white Ally creature token.| +Kyoshi Village|Avatar: The Last Airbender|271|C||Land|||This land enters tapped.${T}: Add {G} or {W}.${4}, {T}, Sacrifice this land: Draw a card.| +Meditation Pools|Avatar: The Last Airbender|272|C||Land|||This land enters tapped.${T}: Add {G} or {U}.${4}, {T}, Sacrifice this land: Draw a card.| +Misty Palms Oasis|Avatar: The Last Airbender|273|C||Land|||This land enters tapped.${T}: Add {W} or {B}.${4}, {T}, Sacrifice this land: Draw a card.| +North Pole Gates|Avatar: The Last Airbender|274|C||Land|||This land enters tapped.${T}: Add {W} or {U}.${4}, {T}, Sacrifice this land: Draw a card.| +Omashu City|Avatar: The Last Airbender|275|C||Land|||This land enters tapped.${T}: Add {R} or {G}.${4}, {T}, Sacrifice this land: Draw a card.| +Realm of Koh|Avatar: The Last Airbender|276|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {B}.${3}{B}, {T}: Create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."| +Rumble Arena|Avatar: The Last Airbender|277|C||Land|||Vigilance$When this land enters, scry 1.${T}: Add {C}.${1}, {T}: Add one mana of any color.| +Secret Tunnel|Avatar: The Last Airbender|278|R||Land - Cave|||This land can't be blocked.${T}: Add {C}.${4}, {T}: Two target creatures you control that share a creature type can't be blocked this turn.| +Serpent's Pass|Avatar: The Last Airbender|279|C||Land|||This land enters tapped.${T}: Add {U} or {B}.${4}, {T}, Sacrifice this land: Draw a card.| +Sun-Blessed Peak|Avatar: The Last Airbender|280|C||Land|||This land enters tapped.${T}: Add {R} or {W}.${4}, {T}, Sacrifice this land: Draw a card.| +White Lotus Hideout|Avatar: The Last Airbender|281|U||Land|||{T}: Add {C}.${T}: Add one mana of any color. Spend this mana only to cast a Lesson or Shrine spell.${1}, {T}: Add one mana of any color.| Plains|Avatar: The Last Airbender|282|C||Basic Land - Plains|||({T}: Add {W}.)| Island|Avatar: The Last Airbender|283|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Avatar: The Last Airbender|284|C||Basic Land - Swamp|||({T}: Add {B}.)| @@ -59856,24 +60086,121 @@ Island|Avatar: The Last Airbender|288|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Avatar: The Last Airbender|289|C||Basic Land - Swamp|||({T}: Add {B}.)| Mountain|Avatar: The Last Airbender|290|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Avatar: The Last Airbender|291|C||Basic Land - Forest|||({T}: Add {G}.)| +Plains|Avatar: The Last Airbender|292|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Avatar: The Last Airbender|293|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Avatar: The Last Airbender|294|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Avatar: The Last Airbender|295|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Avatar: The Last Airbender|296|C||Basic Land - Forest|||({T}: Add {G}.)| +Fated Firepower|Avatar: The Last Airbender|297|M|{X}{R}{R}{R}|Enchantment|||Flash$This enchantment enters with X fire counters on it.$If a source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus an amount of damage equal to the number of fire counters on this enchantment instead.| +Aang, Swift Savior|Avatar: The Last Airbender|298|R|{1}{W}{U}|Legendary Creature - Human Avatar Ally|2|3|Flash$Flying$When Aang enters, airbend up to one other target creature or spell.$Waterbend {8}: Transform Aang.| +Aang and La, Ocean's Fury|Avatar: The Last Airbender|298|R||Legendary Creature - Avatar Spirit Ally|5|5|Reach, trample$Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control.| +Fire Nation Attacks|Avatar: The Last Airbender|299|U|{4}{R}|Instant|||Create two 2/2 red Soldier creature tokens with firebending 1.$Flashback {8}{R}| +Crashing Wave|Avatar: The Last Airbender|300|U|{U}{U}|Sorcery|||As an additional cost to cast this spell, waterbend {X}.$Tap up to X target creatures, then distribute three stun counters among tapped creatures your opponents control.| +Combustion Technique|Avatar: The Last Airbender|301|U|{1}{R}|Instant - Lesson|||Combustion Technique deals damage equal to 2 plus the number of Lesson cards in your graveyard to target creature. If that creature would die this turn, exile it instead.| +Zuko, Conflicted|Avatar: The Last Airbender|302|R|{B}{R}|Legendary Creature - Human Rogue|2|3|At the beginning of your first main phase, choose one that hasn't been chosen and you lose 2 life --$* Draw a card.$* Put a +1/+1 counter on Zuko.$* Add {R}.$* Exile Zuko, then return him to the battlefield under an opponent's control.| +Azula, Cunning Usurper|Avatar: The Last Airbender|303|R|{2}{U}{B}{B}|Legendary Creature - Human Noble Rogue|4|4|Firebending 2$When Azula enters, target opponent exiles a nontoken creature they control, then they exile a nonland card from their graveyard.$During your turn, you may cast cards exiled with Azula and you may cast them as though they had flash. Mana of any type can be spent to cast those spells.| +Aang, at the Crossroads|Avatar: The Last Airbender|304|R|{2}{G}{W}{U}|Legendary Creature - Human Avatar Ally|3|3|Flying$When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.$When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep.| +Aang, Destined Savior|Avatar: The Last Airbender|304|R||Legendary Creature - Avatar Ally|4|4|Flying$Land creatures you control have vigilance.$At the beginning of combat on your turn, earthbend 2.| +Katara, the Fearless|Avatar: The Last Airbender|305|R|{G}{W}{U}|Legendary Creature - Human Warrior Ally|3|3|If a triggered ability of an Ally you control triggers, that ability triggers an additional time.| +Dai Li Agents|Avatar: The Last Airbender|306|U|{3}{B}{G}|Creature - Human Soldier|3|4|When this creature enters, earthbend 1, then earthbend 1.$Whenever this creature attacks, each opponent loses X life and you gain X life, where X is the number of creatures you control with +1/+1 counters on them.| +Earthbender Ascension|Avatar: The Last Airbender|307|R|{2}{G}|Enchantment|||When this enchantment enters, earthbend 2. Then search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Landfall -- Whenever a land you control enters, put a quest counter on this enchantment. When you do, if it has four or more quest counters on it, put a +1/+1 counter on target creature you control. It gains trample until end of turn.| +Avatar Aang|Avatar: The Last Airbender|308|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| +Aang, Master of Elements|Avatar: The Last Airbender|308|M||Legendary Creature - Avatar Ally|6|6|Flying$Spells you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| +Sozin's Comet|Avatar: The Last Airbender|309|M|{3}{R}{R}|Sorcery|||Each creature you control gains firebending 5 until end of turn.$Foretell {2}{R}| +Waterbender Ascension|Avatar: The Last Airbender|310|R|{1}{U}|Enchantment|||Whenever a creature you control deals combat damage to a player, put a quest counter on this enchantment. Then if it has four or more quest counters on it, draw a card.$Waterbend {4}: Target creature can't be blocked this turn.| +Ozai, the Phoenix King|Avatar: The Last Airbender|311|M|{2}{B}{B}{R}{R}|Legendary Creature - Human Noble|7|7|Trample, firebending 4, haste$If you would lose unspent mana, that mana becomes red instead.$Ozai has flying and indestructible as long as you have six or more unspent mana.| +Firebender Ascension|Avatar: The Last Airbender|312|R|{1}{R}|Enchantment|||When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1.$Whenever a creature you control attacking causes a triggered ability of that creature to trigger, put a quest counter on this enchantment. Then if it has four or more quest counters on it, you may copy that ability. You may choose new targets for the copy.| +Fire Lord Azula|Avatar: The Last Airbender|313|R|{1}{U}{B}{R}|Legendary Creature - Human Noble|4|4|Firebending 2$Whenever you cast a spell while Fire Lord Azula is attacking, copy that spell. You may choose new targets for the copy.| +The Last Agni Kai|Avatar: The Last Airbender|314|R|{1}{R}|Instant|||Target creature you control fights target creature an opponent controls. If the creature the opponent controls is dealt excess damage this way, add that much {R}.$Until end of turn, you don't lose unspent red mana as steps and phases end.| +Fire Lord Zuko|Avatar: The Last Airbender|315|R|{R}{W}{B}|Legendary Creature - Human Noble Ally|2|4|Firebending X, where X is Fire Lord Zuko's power.$Whenever you cast a spell from exile and whenever a permanent you control enters from exile, put a +1/+1 counter on each creature you control.| Appa, Steadfast Guardian|Avatar: The Last Airbender|316|M|{2}{W}{W}|Legendary Creature - Bison Ally|3|4|Flash$Flying$When Appa enters, airbend any number of other target nonland permanents you control.$Whenever you cast a spell from exile, create a 1/1 white Ally creature token.| Momo, Friendly Flier|Avatar: The Last Airbender|317|R|{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$The first non-Lemur creature spell with flying you cast during each of your turns costs {1} less to cast.$Whenever another creature you control with flying enters, Momo gets +1/+1 until end of turn.| +Tiger-Seal|Avatar: The Last Airbender|318|R|{U}|Creature - Cat Seal|3|3|Vigilance$At the beginning of your upkeep, tap this creature.$Whenever you draw your second card each turn, untap this creature.| +The Unagi of Kyoshi Island|Avatar: The Last Airbender|319|R|{3}{U}{U}|Legendary Creature - Serpent|5|5|Flash$Ward--Waterbend {4}$Whenever an opponent draws their second card each turn, draw two cards.| +Wan Shi Tong, Librarian|Avatar: The Last Airbender|320|M|{X}{U}{U}|Legendary Creature - Bird Spirit|1|1|Flash$Flying, vigilance$When Wan Shi Tong enters, put X +1/+1 counters on him. Then draw half X cards, rounded down.$Whenever an opponent searches their library, put a +1/+1 counter on Wan Shi Tong and draw a card.| +The Fire Nation Drill|Avatar: The Last Airbender|321|R|{2}{B}{B}|Legendary Artifact - Vehicle|6|3|Trample$When The Fire Nation Drill enters, you may tap it. When you do, destroy target creature with power 4 or less.${1}: Permanents your opponents control lose hexproof and indestructible until end of turn.$Crew 2| +Koh, the Face Stealer|Avatar: The Last Airbender|322|M|{4}{B}{B}|Legendary Creature - Shapeshifter Spirit|6|6|When Koh enters, exile up to one other target creature.$Whenever another nontoken creature dies, you may exile it.$Pay 1 life: Choose a creature card exiled with Koh.$Koh has all activated and triggered abilities of the last chosen card.| +Phoenix Fleet Airship|Avatar: The Last Airbender|323|M|{2}{B}{B}|Artifact - Vehicle|4|4|Flying$At the beginning of your end step, if you sacrificed a permanent this turn, create a token that's a copy of this Vehicle.$As long as you control eight or more permanents named Phoenix Fleet Airship, this Vehicle is an artifact creature.$Crew 1| +Raven Eagle|Avatar: The Last Airbender|324|R|{2}{B}|Creature - Bird Assassin|2|3|Flying$Whenever this creature enters or attacks, exile up to one target card from a graveyard. If a creature card is exiled this way, create a Clue token.$Whenever you draw your second card each turn, each opponent loses 1 life and you gain 1 life.| +Ran and Shaw|Avatar: The Last Airbender|325|R|{3}{R}{R}|Legendary Creature - Dragon|4|4|Flying, firebending 2$When Ran and Shaw enter, if you cast them and there are three or more Dragon and/or Lesson cards in your graveyard, create a token that's a copy of Ran and Shaw, except it's not legendary.${3}{R}: Dragons you control get +2/+0 until end of turn.| +Badgermole Cub|Avatar: The Last Airbender|326|M|{1}{G}|Creature - Badger Mole|2|2|When this creature enters, earthbend 1.$Whenever you tap a creature for mana, add an additional {G}.| +Diligent Zookeeper|Avatar: The Last Airbender|327|R|{3}{G}|Creature - Human Citizen Ally|4|4|Each non-Human creature you control gets +1/+1 for each of its creature types, to a maximum of 10.| +The Lion-Turtle|Avatar: The Last Airbender|328|R|{1}{G}{U}|Legendary Creature - Elder Cat Turtle|3|6|Vigilance, reach$When The Lion-Turtle enters, you gain 3 life.$The Lion-Turtle can't attack or block unless there are three or more Lesson cards in your graveyard.${T}: Add one mana of any color.| +The Walls of Ba Sing Se|Avatar: The Last Airbender|329|M|{8}|Legendary Artifact Creature - Wall|0|30|Defender$Other permanents you control have indestructible.| +White Lotus Tile|Avatar: The Last Airbender|330|M|{4}|Artifact|||This artifact enters tapped.${T}: Add X mana of any one color, where X is the greatest number of creatures you control that have a creature type in common.| +United Front|Avatar: The Last Airbender|331|M|{X}{W}{W}|Sorcery|||Create X 1/1 white Ally creature tokens, then put a +1/+1 counter on each creature you control.| +Sozin's Comet|Avatar: The Last Airbender|332|M|{3}{R}{R}|Sorcery|||Each creature you control gains firebending 5 until end of turn.$Foretell {2}{R}| +Avatar Destiny|Avatar: The Last Airbender|333|R|{2}{G}{G}|Enchantment - Aura|||Enchant creature you control$Enchanted creature gets +1/+1 for each creature card in your graveyard and is an Avatar in addition to its other types.$When enchanted creature dies, mill cards equal to its power. Return this card to its owner's hand and up to one creature card milled this way to the battlefield under your control.| +Fire Lord Azula|Avatar: The Last Airbender|334|R|{1}{U}{B}{R}|Legendary Creature - Human Noble|4|4|Firebending 2$Whenever you cast a spell while Fire Lord Azula is attacking, copy that spell. You may choose new targets for the copy.| +Ozai, the Phoenix King|Avatar: The Last Airbender|335|M|{2}{B}{B}{R}{R}|Legendary Creature - Human Noble|7|7|Trample, firebending 4, haste$If you would lose unspent mana, that mana becomes red instead.$Ozai has flying and indestructible as long as you have six or more unspent mana.| Aang's Iceberg|Avatar: The Last Airbender|336|R|{2}{W}|Enchantment|||Flash$When this enchantment enters, exile up to one other target nonland permanent until this enchantment leaves the battlefield.$Waterbend {3}: Sacrifice this enchantment. If you do, scry 2.| +Secret of Bloodbending|Avatar: The Last Airbender|337|M|{U}{U}{U}{U}|Sorcery - Lesson|||As an additional cost to cast this spell, you may waterbend {10}.$You control target opponent during their next combat phase. If this spell's additional cost was paid, you control that player during their next turn instead.$Exile Secret of Bloodbending.| Yue, the Moon Spirit|Avatar: The Last Airbender|338|R|{3}{U}|Legendary Creature - Spirit Ally|3|3|Flying, vigilance$Waterbend {5}, {T}: You may cast a noncreature spell from your hand without paying its mana cost.| +Foggy Swamp Visions|Avatar: The Last Airbender|339|R|{1}{B}{B}|Sorcery|||As an additional cost to cast this spell, waterbend {X}.$Exile X target creature cards from graveyards. For each creature card exiled this way, create a token that's a copy of it. At the beginning of your next end step, sacrifice those tokens.| +Obsessive Pursuit|Avatar: The Last Airbender|340|R|{1}{B}|Enchantment|||When this enchantment enters and at the beginning of your upkeep, you lose 1 life and create a Clue token.$Whenever you attack, put X +1/+1 counters on target attacking creature, where X is the number of permanents you've sacrificed this turn. If X is three or greater, that creature gains lifelink until end of turn.| Fated Firepower|Avatar: The Last Airbender|341|M|{X}{R}{R}{R}|Enchantment|||Flash$This enchantment enters with X fire counters on it.$If a source you control would deal damage to an opponent or a permanent an opponent controls, it deals that much damage plus an amount of damage equal to the number of fire counters on this enchantment instead.| +Firebending Student|Avatar: The Last Airbender|342|R|{1}{R}|Creature - Human Monk|1|2|Prowess$Firebending X, where X is this creature's power.| Redirect Lightning|Avatar: The Last Airbender|343|R|{R}|Instant - Lesson|||As an additional cost to cast this spell, pay 5 life or pay {2}.$Change the target of target spell or ability with a single target.| +The Earth King|Avatar: The Last Airbender|344|R|{3}{G}|Legendary Creature - Human Noble Ally|2|2|When The Earth King enters, create a 4/4 green Bear creature token.$Whenever one or more creatures you control with power 4 or greater attack, search your library for up to that many basic land cards, put them onto the battlefield tapped, then shuffle.| +Great Divide Guide|Avatar: The Last Airbender|345|R|{1}{G}|Creature - Human Scout Ally|2|3|Each land and Ally you control has "{T}: Add one mana of any color."| +Aang, at the Crossroads|Avatar: The Last Airbender|346|R|{2}{G}{W}{U}|Legendary Creature - Human Avatar Ally|3|3|Flying$When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.$When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep.| +Aang, Destined Savior|Avatar: The Last Airbender|346|R||Legendary Creature - Avatar Ally|4|4|Flying$Land creatures you control have vigilance.$At the beginning of combat on your turn, earthbend 2.| +Aang, Swift Savior|Avatar: The Last Airbender|347|R|{1}{W}{U}|Legendary Creature - Human Avatar Ally|2|3|Flash$Flying$When Aang enters, airbend up to one other target creature or spell.$Waterbend {8}: Transform Aang.| +Aang and La, Ocean's Fury|Avatar: The Last Airbender|347|R||Legendary Creature - Avatar Spirit Ally|5|5|Reach, trample$Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control.| +Bumi, Unleashed|Avatar: The Last Airbender|348|M|{3}{R}{G}|Legendary Creature - Human Noble Ally|5|4|Trample$When Bumi enters, earthbend 4.$Whenever Bumi deals combat damage to a player, untap all lands you control. After this phase, there is an additional combat phase. Only land creatures can attack during that combat phase.| +Iroh, Grand Lotus|Avatar: The Last Airbender|349|R|{3}{G}{U}{R}|Legendary Creature - Human Noble Ally|5|5|Firebending 2$During your turn, each non-Lesson instant and sorcery card in your graveyard has flashback. The flashback cost is equal to that card's mana cost.$During your turn, each Lesson card in your graveyard has flashback {1}.| Katara, the Fearless|Avatar: The Last Airbender|350|R|{G}{W}{U}|Legendary Creature - Human Warrior Ally|3|3|If a triggered ability of an Ally you control triggers, that ability triggers an additional time.| Katara, Water Tribe's Hope|Avatar: The Last Airbender|351|R|{2}{W}{U}{U}|Legendary Creature - Human Warrior Ally|3|3|Vigilance$When Katara enters, create a 1/1 white Ally creature token.$Waterbend {X}: Creatures you control have base power and toughness X/X until end of turn. X can't be 0. Activate only during your turn.| +Sokka, Tenacious Tactician|Avatar: The Last Airbender|352|R|{1}{U}{R}{W}|Legendary Creature - Human Warrior Ally|3|3|Menace, prowess$Other Allies you control have menace and prowess.$Whenever you cast a noncreature spell, create a 1/1 white Ally creature token.| Toph, the First Metalbender|Avatar: The Last Airbender|353|R|{1}{R}{G}{W}|Legendary Creature - Human Warrior Ally|3|3|Nontoken artifacts you control are lands in addition to their other types.$At the beginning of your end step, earthbend 2.| +The Legend of Yangchen|Avatar: The Last Airbender|354|M|{3}{W}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I -- Starting with you, each player chooses up to one permanent with mana value 3 or greater from among permanents your opponents control. Exile those permanents.$II -- You may have target opponent draw three cards. If you do, draw three cards.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Yangchen|Avatar: The Last Airbender|354|M||Legendary Creature - Avatar|4|5|Flying$Whenever you cast your second spell each turn, airbend up to one other target nonland permanent.| +The Legend of Kuruk|Avatar: The Last Airbender|355|M|{2}{U}{U}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I, II -- Scry 2, then draw a card.$III -- Exile this Saga, then return it to the battlefield$transformed under your control.| +Avatar Kuruk|Avatar: The Last Airbender|355|M||Legendary Creature - Avatar|4|3|Whenever you cast a spell, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."$Exhaust -- Waterbend {20}: Take an extra turn after this one.| The Rise of Sozin|Avatar: The Last Airbender|356|M|{4}{B}{B}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I -- Destroy all creatures.$II -- Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. Then that player shuffles.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| Fire Lord Sozin|Avatar: The Last Airbender|356|M||Legendary Creature - Human Noble|5|5|Menace, firebending 3$Whenever Fire Lord Sozin deals combat damage to a player, you may pay {X}. When you do, put any number of target creature cards with total mana value X or less from that player's graveyard onto the battlefield under your control.| +The Legend of Roku|Avatar: The Last Airbender|357|M|{2}{R}{R}|Enchantment - Saga|||(As this Saga enters and after your draw$step, add a lore counter.)$I -- Exile the top three cards of your library. Until the end of your next turn, you may play those cards.$II -- Add one mana of any color.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Roku|Avatar: The Last Airbender|357|M||Legendary Creature - Avatar|4|4|Firebending 4${8}: Create a 4/4 red Dragon creature token with flying and firebending 4.| +The Legend of Kyoshi|Avatar: The Last Airbender|358|M|{4}{G}{G}|Enchantment - Saga|||(As this Saga enters and after your draw$step, add a lore counter.)$I -- Draw cards equal to the greatest power among creatures you control.$II -- Earthbend X, where X is the number of cards in your hand. That land becomes an Island in addition to its other types.$III -- Exile this Saga, then return it to the battlefield transformed under your control.| +Avatar Kyoshi|Avatar: The Last Airbender|358|M||Legendary Creature - Avatar|5|4|Lands you control have trample and hexproof.${T}: Add X mana of any one color, where X is the greatest power among creatures you control.| +Aang, Swift Savior|Avatar: The Last Airbender|359|R|{1}{W}{U}|Legendary Creature - Human Avatar Ally|2|3|Flash$Flying$When Aang enters, airbend up to one other target creature or spell.$Waterbend {8}: Transform Aang.| +Aang and La, Ocean's Fury|Avatar: The Last Airbender|359|R||Legendary Creature - Avatar Spirit Ally|5|5|Reach, trample$Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control.| Fire Lord Zuko|Avatar: The Last Airbender|360|R|{R}{W}{B}|Legendary Creature - Human Noble Ally|2|4|Firebending X, where X is Fire Lord Zuko's power.$Whenever you cast a spell from exile and whenever a permanent you control enters from exile, put a +1/+1 counter on each creature you control.| Katara, the Fearless|Avatar: The Last Airbender|361|R|{G}{W}{U}|Legendary Creature - Human Warrior Ally|3|3|If a triggered ability of an Ally you control triggers, that ability triggers an additional time.| Toph, the First Metalbender|Avatar: The Last Airbender|362|R|{1}{R}{G}{W}|Legendary Creature - Human Warrior Ally|3|3|Nontoken artifacts you control are lands in addition to their other types.$At the beginning of your end step, earthbend 2.| Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spells you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| +Airbender Ascension|Avatar: The Last Airbender|364|R|{1}{W}|Enchantment|||When this enchantment enters, airbend up to one target creature.$Whenever a creature you control enters, put a quest counter on this enchantment.$At the beginning of your end step, if this enchantment has four or more quest counters on it, exile up to one target creature you control, then return it to the battlefield under its owner's control.| +Avatar's Wrath|Avatar: The Last Airbender|365|R|{2}{W}{W}|Sorcery|||Choose up to one target creature, then airbend all other creatures.$Until your next turn, your opponents can't cast spells from anywhere other than their hand.$Exile Avatar's Wrath.| Hakoda, Selfless Commander|Avatar: The Last Airbender|366|R|{3}{W}|Legendary Creature - Human Warrior Ally|3|5|Vigilance$You may look at the top card of your library any time.$You may cast Ally spells from the top of your library.$Sacrifice Hakoda: Creatures you control get +0/+5 and gain indestructible until end of turn.| +South Pole Voyager|Avatar: The Last Airbender|367|R|{1}{W}|Creature - Human Scout Ally|2|2|Whenever this creature or another Ally you control enters, you gain 1 life. If this is the second time this ability has resolved this turn, draw a card.| +Suki, Courageous Rescuer|Avatar: The Last Airbender|368|R|{1}{W}{W}|Legendary Creature - Human Warrior Ally|2|4|Other creatures you control get +1/+0.$Whenever another permanent you control leaves the battlefield during your turn, create a 1/1 white Ally creature token. This ability triggers only once each turn.| +The Mechanist, Aerial Artisan|Avatar: The Last Airbender|369|R|{2}{U}|Legendary Creature - Human Artificer Ally|1|3|Whenever you cast a noncreature spell, create a Clue token.${T}: Until end of turn, target artifact token you control becomes a 3/1 Construct artifact creature with flying.| +Spirit Water Revival|Avatar: The Last Airbender|370|R|{1}{U}{U}|Sorcery|||As an additional cost to cast this spell, you may waterbend {6}.$Draw two cards. If this spell's additional cost was paid, instead shuffle your graveyard into your library, draw seven cards, and you have no maximum hand size for the rest of the game.$Exile Spirit Water Revival.| +Ty Lee, Chi Blocker|Avatar: The Last Airbender|371|R|{2}{U}|Legendary Creature - Human Performer Ally|2|1|Flash$Prowess$When Ty Lee enters, tap up to one target creature. It doesn't untap during its controller's untap step for as long as you control Ty Lee.| +Boiling Rock Rioter|Avatar: The Last Airbender|372|R|{2}{B}|Creature - Human Rogue Ally|3|3|Firebending 1$Tap an untapped Ally you control: Exile target card from a graveyard.$Whenever this creature attacks, you may cast an Ally spell from among cards you own exiled with this creature.| +Day of Black Sun|Avatar: The Last Airbender|373|R|{X}{B}{B}|Sorcery|||Each creature with mana value X or less loses all abilities until end of turn. Destroy those creatures.| +Mai, Scornful Striker|Avatar: The Last Airbender|374|R|{1}{B}|Legendary Creature - Human Noble Ally|2|2|First strike$Whenever a player casts a noncreature spell, they lose 2 life.| +Wartime Protestors|Avatar: The Last Airbender|375|R|{3}{R}|Creature - Human Rebel Ally|4|4|Haste$Whenever another Ally you control enters, put a +1/+1 counter on that creature and it gains haste until end of turn.| +Zhao, the Moon Slayer|Avatar: The Last Airbender|376|R|{1}{R}|Legendary Creature - Human Soldier|2|2|Menace$Nonbasic lands enter tapped.${7}: Put a conqueror counter on Zhao.$As long as Zhao has a conqueror counter on him, nonbasic lands are Mountains.| +Earthen Ally|Avatar: The Last Airbender|377|R|{G}|Creature - Human Soldier Ally|0|2|This creature gets +1/+0 for each color among Allies you control.${2}{W}{U}{B}{R}{G}: Earthbend 5.| +Elemental Teachings|Avatar: The Last Airbender|378|R|{4}{G}|Instant - Lesson|||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 onto the battlefield tapped, then shuffle.| +Beifong's Bounty Hunters|Avatar: The Last Airbender|379|R|{2}{B}{G}|Creature - Human Mercenary|4|4|Whenever a nonland creature you control dies, earthbend X, where X is that creature's power.| +Earth King's Lieutenant|Avatar: The Last Airbender|380|R|{G}{W}|Creature - Human Soldier Ally|1|1|Trample$When this creature enters, put a +1/+1 counter on each other Ally creature you control.$Whenever another Ally you control enters, put a +1/+1 counter on this creature.| +Iroh, Tea Master|Avatar: The Last Airbender|381|R|{1}{R}{W}|Legendary Creature - Human Citizen Ally|2|2|When Iroh enters, create a Food token.$At the beginning of combat on your turn, you may have target opponent gain control of target permanent you control. When you do, create a 1/1 white Ally creature token. Put a +1/+1 counter on that token for each permanent you own that your opponents control.| +Sandbender Scavengers|Avatar: The Last Airbender|382|R|{W}{B}|Creature - Human Rogue|1|1|Whenever you sacrifice another permanent, put a +1/+1 counter on this creature.$When this creature dies, you may exile it. When you do, return target creature card with mana value less than or equal to this creature's power from your graveyard to the battlefield.| Sokka, Bold Boomeranger|Avatar: The Last Airbender|383|R|{U}{R}|Legendary Creature - Human Warrior Ally|1|1|When Sokka enters, discard up to two cards, then draw that many cards.$Whenever you cast an artifact or Lesson spell, put a +1/+1 counter on Sokka.| +Toph, Hardheaded Teacher|Avatar: The Last Airbender|384|R|{2}{R}{G}|Legendary Creature - Human Warrior Ally|3|4|When Toph enters, you may discard a card. If you do, return target instant or sorcery card from your graveyard to your hand.$Whenever you cast a spell, earthbend 1. If that spell is a Lesson, put an additional +1/+1 counter on that land.| +Planetarium of Wan Shi Tong|Avatar: The Last Airbender|385|M|{6}|Legendary Artifact|||{1}, {T}: Scry 2.$Whenever you scry or surveil, look at the top card of your library. You may cast that card without paying its mana cost. Do this only once each turn.| +Abandoned Air Temple|Avatar: The Last Airbender|386|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {W}.${3}{W}, {T}: Put a +1/+1 counter on each creature you control.| +Agna Qel'a|Avatar: The Last Airbender|387|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {U}.${2}{U}, {T}: Draw a card, then discard a card.| +Ba Sing Se|Avatar: The Last Airbender|388|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {G}.${2}{G}, {T}: Earthbend 2. Activate only as a sorcery.| +Fire Nation Palace|Avatar: The Last Airbender|389|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {R}.${1}{R}, {T}: Target creature you control gains firebending 4 until end of turn.| +Jasmine Dragon Tea Shop|Avatar: The Last Airbender|390|R||Land|||{T}: Add {C}.${T}: Add one mana of any color. Spend this mana only to cast an Ally spell or activate an ability of an Ally source.${5}, {T}: Create a 1/1 white Ally creature token.| +Realm of Koh|Avatar: The Last Airbender|391|R||Land|||This land enters tapped unless you control a basic land.${T}: Add {B}.${3}{B}, {T}: Create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."| +Secret Tunnel|Avatar: The Last Airbender|392|R||Land - Cave|||This land can't be blocked.${T}: Add {C}.${4}, {T}: Two target creatures you control that share a creature type can't be blocked this turn.| +Firebending Student|Avatar: The Last Airbender|393|R|{1}{R}|Creature - Human Monk|1|2|Prowess$Firebending X, where X is this creature's power.| +Momo, Friendly Flier|Avatar: The Last Airbender|394|R|{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$The first non-Lemur creature spell with flying you cast during each of your turns costs {1} less to cast.$Whenever another creature you control with flying enters, Momo gets +1/+1 until end of turn.| Anti-Venom, Horrifying Healer|Marvel's Spider-Man|1|M|{W}{W}{W}{W}{W}|Legendary Creature - Symbiote Hero|5|5|When Anti-Venom enters, if he was cast, return target creature card from your graveyard to the battlefield.$If damage would be dealt to Anti-Venom, prevent that damage and put that many +1/+1 counters on him.| Arachne, Psionic Weaver|Marvel's Spider-Man|2|R|{2}{W}|Legendary Creature - Spider Human Hero|3|3|Web-slinging {W}$As Arachne enters, look at target opponent's hand, then choose a noncreature card type.$Spells of the chosen type cost {1} more to cast.| Aunt May|Marvel's Spider-Man|3|U|{W}|Legendary Creature - Human Citizen|0|2|Whenever another creature you control enters, you gain 1 life. If it's a Spider, put a +1/+1 counter on it.| @@ -60174,12 +60501,215 @@ Urban Retreat|Marvel's Spider-Man|283|R||Land|||This land enters tapped.${T}: Ad Spider-Sense|Marvel's Spider-Man|284|R|{1}{U}|Instant|||Web-slinging {U}$Counter target instant spell, sorcery spell, or triggered ability.| Radioactive Spider|Marvel's Spider-Man|285|R|{G}|Creature - Spider|1|1|Reach, deathtouch$Fateful Bite -- {2}, Sacrifice this creature: Search your library for a Spider Hero card, reveal it, put it into your hand, then shuffle. Activate only as a sorcery.| Gwenom, Remorseless|Marvel's Spider-Man|286|M|{3}{B}{B}|Legendary Creature - Symbiote Spider Hero|4|4|Deathtouch, lifelink$Whenever Gwenom attacks, until end of turn you may look at the top card of your library any time and you may play cards from the top of your library. If you cast a spell this way, pay life equal to its mana value rather than pay its mana cost.| +Brought Back|Avatar: The Last Airbender Eternal|1|M|{W}{W}|Instant|||Choose up to two target permanent cards in your graveyard that were put there from the battlefield this turn. Return them to the battlefield tapped.| +Drannith Magistrate|Avatar: The Last Airbender Eternal|2|M|{1}{W}|Creature - Human Wizard|1|3|Your opponents can't cast spells from anywhere other than their hands.| +Empty City Ruse|Avatar: The Last Airbender Eternal|3|M|{W}|Sorcery|||Target opponent skips all combat phases of their next turn.| +Lita, Mechanical Engineer|Avatar: The Last Airbender Eternal|4|M|{2}{W}|Legendary Artifact Creature - Artificer|3|3|Vigilance$At the beginning of your end step, untap each other artifact creature you control.${3}{W}, {T}: Create a 5/5 colorless Vehicle artifact token named Zeppelin with flying and crew 3.| +Release to Memory|Avatar: The Last Airbender Eternal|5|M|{3}{W}|Instant|||Exile target opponent's graveyard. For each creature card exiled this way, create a 1/1 colorless Spirit creature token.| +Scout's Warning|Avatar: The Last Airbender Eternal|6|M|{W}|Instant|||The next creature card you play this turn can be played as though it had flash.$Draw a card.| +Teferi's Protection|Avatar: The Last Airbender Eternal|7|M|{2}{W}|Instant|||Until your next turn, your life total can't change and you gain protection from everything. All permanents you control phase out.$Exile Teferi's Protection.| +Three Dreams|Avatar: The Last Airbender Eternal|8|M|{4}{W}|Sorcery|||Search your library for up to three Aura cards with different names, reveal them, put them into your hand, then shuffle.| +Agent of Treachery|Avatar: The Last Airbender Eternal|9|M|{5}{U}{U}|Creature - Human Rogue|2|3|When this creature enters, gain control of target permanent.$At the beginning of your end step, if you control three or more permanents you don't own, draw three cards.| +Bribery|Avatar: The Last Airbender Eternal|10|M|{3}{U}{U}|Sorcery|||Search target opponent's library for a creature card and put that card onto the battlefield under your control. Then that player shuffles.| +Clone|Avatar: The Last Airbender Eternal|11|M|{3}{U}|Creature - Shapeshifter|0|0|You may have this creature enter as a copy of any creature on the battlefield.| +Clone Legion|Avatar: The Last Airbender Eternal|12|M|{7}{U}{U}|Sorcery|||For each creature target player controls, create a token that's a copy of that creature.| Force of Negation|Avatar: The Last Airbender Eternal|13|M|{1}{U}{U}|Instant|||If it's not your turn, you may exile a blue card from your hand rather than pay this spell's mana cost.$Counter target noncreature spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard.| +Imprisoned in the Moon|Avatar: The Last Airbender Eternal|14|M|{2}{U}|Enchantment - Aura|||Enchant creature, land, or planeswalker$Enchanted permanent is a colorless land with "{T}: Add {C}" and loses all other card types and abilities.| +Intruder Alarm|Avatar: The Last Airbender Eternal|15|M|{2}{U}|Enchantment|||Creatures don't untap during their controllers' untap steps.$Whenever a creature enters, untap all creatures.| +Mystic Remora|Avatar: The Last Airbender Eternal|16|M|{U}|Enchantment|||Cumulative upkeep {1}$Whenever an opponent casts a noncreature spell, you may draw a card unless that player pays {4}.| +Prosperity|Avatar: The Last Airbender Eternal|17|M|{X}{U}|Sorcery|||Each player draws X cards.| +Sakashima of a Thousand Faces|Avatar: The Last Airbender Eternal|18|M|{3}{U}|Legendary Creature - Human Rogue|3|1|You may have Sakashima enter as a copy of another creature you control, except it has Sakashima's other abilities.$The "legend rule" doesn't apply to permanents you control.$Partner| +Standstill|Avatar: The Last Airbender Eternal|19|M|{1}{U}|Enchantment|||When a player casts a spell, sacrifice this enchantment. If you do, each of that player's opponents draws three cards.| +Training Grounds|Avatar: The Last Airbender Eternal|20|M|{U}|Enchantment|||Activated abilities of creatures you control cost {2} less to activate. This effect can't reduce the mana in that cost to less than one mana.| +Visions of Beyond|Avatar: The Last Airbender Eternal|21|M|{U}|Instant|||Draw a card. If a graveyard has twenty or more cards in it, draw three cards instead.| +Black Sun's Zenith|Avatar: The Last Airbender Eternal|22|M|{X}{B}{B}|Sorcery|||Put X -1/-1 counters on each creature. Shuffle Black Sun's Zenith into its owner's library.| +Bloodchief Ascension|Avatar: The Last Airbender Eternal|23|M|{B}|Enchantment|||At the beginning of each end step, if an opponent lost 2 or more life this turn, you may put a quest counter on this enchantment.$Whenever a card is put into an opponent's graveyard from anywhere, if this enchantment has three or more quest counters on it, you may have that player lose 2 life. If you do, you gain 2 life.| +Cruel Tutor|Avatar: The Last Airbender Eternal|24|M|{2}{B}|Sorcery|||Search your library for a card, then shuffle and put that card on top. You lose 2 life.| +Noxious Gearhulk|Avatar: The Last Airbender Eternal|25|M|{4}{B}{B}|Artifact Creature - Construct|5|4|Menace$When this creature enters, you may destroy another target creature. If a creature is destroyed this way, you gain life equal to its toughness.| +Blasphemous Act|Avatar: The Last Airbender Eternal|26|M|{8}{R}|Sorcery|||This spell costs {1} less to cast for each creature on the battlefield.$Blasphemous Act deals 13 damage to each creature.| +Diaochan, Artful Beauty|Avatar: The Last Airbender Eternal|27|M|{3}{R}|Legendary Creature - Human Advisor|1|1|{T}: Destroy target creature of your choice, then destroy target creature of an opponent's choice. Activate only during your turn, before attackers are declared.| +Dockside Extortionist|Avatar: The Last Airbender Eternal|28|M|{1}{R}|Creature - Goblin Pirate|1|2|When this creature enters, create X Treasure tokens, where X is the number of artifacts and enchantments your opponents control.| +Fervor|Avatar: The Last Airbender Eternal|29|M|{2}{R}|Enchantment|||Creatures you control have haste.| +Humble Defector|Avatar: The Last Airbender Eternal|30|M|{1}{R}|Creature - Human Rogue|2|1|{T}: Draw two cards. Target opponent gains control of this creature. Activate only during your turn.| +Insurrection|Avatar: The Last Airbender Eternal|31|M|{5}{R}{R}{R}|Sorcery|||Untap all creatures and gain control of them until end of turn. They gain haste until end of turn.| +Lightning Bolt|Avatar: The Last Airbender Eternal|32|M|{R}|Instant|||Lightning Bolt deals 3 damage to any target.| +Mirrorwing Dragon|Avatar: The Last Airbender Eternal|33|M|{3}{R}{R}|Creature - Dragon|4|5|Flying$Whenever a player casts an instant or sorcery spell that targets only this creature, that player copies that spell for each other creature they control that the spell could target. Each copy targets a different one of those creatures.| +Rending Volley|Avatar: The Last Airbender Eternal|34|M|{R}|Instant|||This spell can't be countered.$Rending Volley deals 4 damage to target white or blue creature.| +Searing Blood|Avatar: The Last Airbender Eternal|35|M|{R}{R}|Instant|||Searing Blood deals 2 damage to target creature. When that creature dies this turn, Searing Blood deals 3 damage to the creature's controller.| +Shattering Spree|Avatar: The Last Airbender Eternal|36|M|{R}|Sorcery|||Replicate {R}$Destroy target artifact.| +Volcanic Torrent|Avatar: The Last Airbender Eternal|37|M|{4}{R}|Sorcery|||Cascade$Volcanic Torrent deals X damage to each creature and planeswalker your opponents control, where X is the number of spells you've cast this turn.| +Warstorm Surge|Avatar: The Last Airbender Eternal|38|M|{5}{R}|Enchantment|||Whenever a creature you control enters, it deals damage equal to its power to any target.| +Beastmaster Ascension|Avatar: The Last Airbender Eternal|39|M|{2}{G}|Enchantment|||Whenever a creature you control attacks, you may put a quest counter on this enchantment.$As long as this enchantment has seven or more quest counters on it, creatures you control get +5/+5.| +Elemental Bond|Avatar: The Last Airbender Eternal|40|M|{2}{G}|Enchantment|||Whenever a creature you control with power 3 or greater enters, draw a card.| The Great Henge|Avatar: The Last Airbender Eternal|41|M|{7}{G}{G}|Legendary Artifact|||This spell costs {X} less to cast, where X is the greatest power among creatures you control.${T}: Add {G}{G}. You gain 2 life.$Whenever a nontoken creature you control enters, put a +1/+1 counter on it and draw a card.| +Heartbeat of Spring|Avatar: The Last Airbender Eternal|42|M|{2}{G}|Enchantment|||Whenever a player taps a land for mana, that player adds one mana of any type that land produced.| +Heroic Intervention|Avatar: The Last Airbender Eternal|43|M|{1}{G}|Instant|||Permanents you control gain hexproof and indestructible until end of turn.| +Return of the Wildspeaker|Avatar: The Last Airbender Eternal|44|M|{4}{G}|Instant|||Choose one --$* Draw cards equal to the greatest power among non-Human creatures you control.$* Non-Human creatures you control get +3/+3 until end of turn.| +Rites of Flourishing|Avatar: The Last Airbender Eternal|45|M|{2}{G}|Enchantment|||At the beginning of each player's draw step, that player draws an additional card.$Each player may play an additional land on each of their turns.| +Taunting Challenge|Avatar: The Last Airbender Eternal|46|M|{1}{G}{G}|Sorcery|||All creatures able to block target creature this turn do so.| +Captain Sisay|Avatar: The Last Airbender Eternal|47|M|{2}{G}{W}|Legendary Creature - Human Soldier|2|2|{T}: Search your library for a legendary card, reveal that card, put it into your hand, then shuffle.| +Eladamri's Call|Avatar: The Last Airbender Eternal|48|M|{G}{W}|Instant|||Search your library for a creature card, reveal that card, put it into your hand, then shuffle.| +Fevered Visions|Avatar: The Last Airbender Eternal|49|R|{1}{U}{R}|Enchantment|||At the beginning of each player's end step, that player draws a card. If the player is your opponent and has four or more cards in hand, this enchantment deals 2 damage to that player.| +Join the Dance|Avatar: The Last Airbender Eternal|50|U|{G}{W}|Sorcery|||Create two 1/1 white Human creature tokens.$Flashback {3}{G}{W}| +Koma, Cosmos Serpent|Avatar: The Last Airbender Eternal|51|M|{3}{G}{G}{U}{U}|Legendary Creature - Serpent|6|6|This spell can't be countered.$At the beginning of each upkeep, create a 3/3 blue Serpent creature token named Koma's Coil.$Sacrifice another Serpent: Choose one --$* Tap target permanent. Its activated abilities can't be activated this turn.$* Koma gains indestructible until end of turn.| +Rhys the Redeemed|Avatar: The Last Airbender Eternal|52|M|{G/W}|Legendary Creature - Elf Warrior|1|1|{2}{G/W}, {T}: Create a 1/1 green and white Elf Warrior creature token.${4}{G/W}{G/W}, {T}: For each creature token you control, create a token that's a copy of that creature.| +Cityscape Leveler|Avatar: The Last Airbender Eternal|53|M|{8}|Artifact Creature - Construct|8|8|Trample$When you cast this spell and whenever this creature attacks, destroy up to one target nonland permanent. Its controller creates a tapped Powerstone token.$Unearth {8}| +Meteorite|Avatar: The Last Airbender Eternal|54|M|{5}|Artifact|||When this artifact enters, it deals 2 damage to any target.${T}: Add one mana of any color.| +Sundial of the Infinite|Avatar: The Last Airbender Eternal|55|M|{2}|Artifact|||{1}, {T}: End the turn. Activate only during your turn.| +Dark Depths|Avatar: The Last Airbender Eternal|56|M||Legendary Snow Land|||Dark Depths enters with ten ice counters on it.${3}: Remove an ice counter from Dark Depths.$When Dark Depths has no ice counters on it, sacrifice it. If you do, create Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible.| +Fabled Passage|Avatar: The Last Airbender Eternal|57|M||Land|||{T}, Sacrifice this land: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle. Then if you control four or more lands, untap that land.| +Sunbaked Canyon|Avatar: The Last Airbender Eternal|58|M||Land|||{T}, Pay 1 life: Add {R} or {W}.${1}, {T}, Sacrifice this land: Draw a card.| +Tarnished Citadel|Avatar: The Last Airbender Eternal|59|M||Land|||{T}: Add {C}.${T}: Add one mana of any color. This land deals 3 damage to you.| +Treetop Village|Avatar: The Last Airbender Eternal|60|M||Land|||This land enters tapped.${T}: Add {G}.${1}{G}: This land becomes a 3/3 green Ape creature with trample until end of turn. It's still a land.| +Valakut, the Molten Pinnacle|Avatar: The Last Airbender Eternal|61|M||Land|||This land enters tapped.$Whenever a Mountain you control enters, if you control at least five other Mountains, you may have this land deal 3 damage to any target.${T}: Add {R}.| +Appa, the Vigilant|Avatar: The Last Airbender Eternal|62|R|{5}{W}{W}|Legendary Creature - Bison Ally|6|6|Flying, vigilance$Whenever Appa or another Ally you control enters, creatures you control get +1/+1 and gain flying and vigilance until end of turn.| +Katara's Reversal|Avatar: The Last Airbender Eternal|63|R|{2}{U}{U}|Instant|||Counter up to four target spells and/or abilities.$Untap up to four target artifacts and/or creatures.| +Fire Nation Turret|Avatar: The Last Airbender Eternal|64|R|{2}{R}|Artifact|||At the beginning of combat on your turn, up to one target creature gets +2/+0 and gains firebending 2 until end of turn.${R}: Put a charge counter on this artifact.$Remove fifty charge counters from this artifact: It deals 50 damage to any target.| +Swampbenders|Avatar: The Last Airbender Eternal|65|R|{4}{G}{G}|Creature - Human Druid Ally|*|*|Swampbenders's power and toughness are each equal to the number of Swamps on the battlefield. Lands you control are Swamps in addition to their other types.| +Sokka's Charge|Avatar: The Last Airbender Eternal|66|R|{3}{W}|Enchantment|||During your turn, Allies you control have double strike and lifelink.| +Earthshape|Avatar: The Last Airbender Eternal|67|R|{2}{W}|Instant|||Earthbend 3. Then each creature you control with power less than or equal to that land's power gains hexproof and indestructible until end of turn. You gain hexproof until end of turn.| +Mai and Zuko|Avatar: The Last Airbender Eternal|68|R|{1}{U}{B}{R}|Legendary Creature - Human Noble Ally|3|5|Firebending 3$You may cast Ally spells and artifact spells as though they had flash.| +Aang and Katara|Avatar: The Last Airbender Eternal|69|R|{3}{G}{W}{U}|Legendary Creature - Human Avatar Ally|5|5|Whenever Aang and Katara enter or attack, create X 1/1 white Ally creature tokens, where X is the number of tapped artifacts and/or creatures you control.| +Toph, Greatest Earthbender|Avatar: The Last Airbender Eternal|70|R|{2}{R}{G}|Legendary Creature - Human Warrior Ally|3|3|When Toph enters, earthbend X, where X is the amount of mana spent to cast her.$Land creatures you control have double strike.| +Sokka and Suki|Avatar: The Last Airbender Eternal|71|R|{U}{R}{W}|Legendary Creature - Human Warrior Ally|3|3|Whenever Sokka and Suki or another Ally you control enters, attach up to one target Equipment you control to that creature.$Whenever an Equipment you control enters, create a 1/1 white Ally creature token.| +Momo's Heist|Avatar: The Last Airbender Eternal|72|R|{2}{R}|Sorcery|||Gain control of target artifact. Untap it. It gains haste. At the beginning of the next end step, sacrifice it.| +Uncle's Musings|Avatar: The Last Airbender Eternal|73|R|{2}{G}{G}|Sorcery|||Converge -- Return up to X permanent cards from your graveyard to your hand, where X is the number of colors of mana spent to cast this spell.$Exile Uncle's Musings.| Aang, Airbending Master|Avatar: The Last Airbender Eternal|74|M|{4}{W}|Legendary Creature - Human Avatar Ally|4|4|When Aang enters, airbend another target creature.$Whenever one or more creatures you control leave the battlefield without dying, you get an experience counter.$At the beginning of your upkeep, create a 1/1 white Ally creature token for each experience counter you have.| +Air Nomad Student|Avatar: The Last Airbender Eternal|75|U|{3}{W}|Creature - Human Monk|2|2|Flying$At the beginning of your end step, if this creature didn't attack this turn, put a +1/+1 counter on it.| +The Duke, Rebel Sentry|Avatar: The Last Airbender Eternal|76|U|{W}|Legendary Creature - Human Rebel Ally|0|1|The Duke enters with a +1/+1 counter on him.${T}, Remove a counter from The Duke: Put a +1/+1 counter on another target creature you control. It gains hexproof until end of turn.| +Inspired Insurgent|Avatar: The Last Airbender Eternal|77|C|{1}{W}|Creature - Human Peasant Ally|2|2|{1}, Sacrifice this creature: Destroy target artifact or enchantment.| +Jet, Rebel Leader|Avatar: The Last Airbender Eternal|78|R|{3}{W}|Legendary Creature - Human Rebel Ally|3|4|Whenever Jet attacks, look at the top five cards of your library. You may put a creature card with mana value 3 or less from among them onto the battlefield tapped and attacking. Put the rest on the bottom of your library in a random order.| +Kindly Customer|Avatar: The Last Airbender Eternal|79|C|{1}{W}|Creature - Human Citizen|1|1|When this creature enters, draw a card.| +Koala-Sheep|Avatar: The Last Airbender Eternal|80|C|{2}{W}|Creature - Bear Sheep|3|2|When this creature enters, you gain 3 life.| +Monk Gyatso|Avatar: The Last Airbender Eternal|81|R|{3}{W}|Legendary Creature - Human Monk|3|3|Whenever another creature you control becomes the target of a spell or ability, you may airbend that creature.| +Pipsqueak, Rebel Strongarm|Avatar: The Last Airbender Eternal|82|U|{2}{W}|Legendary Creature - Human Rebel Ally|4|4|Pipsqueak can't attack alone unless he has a +1/+1 counter on him.| +Sokka, Swordmaster|Avatar: The Last Airbender Eternal|83|M|{2}{W}|Legendary Creature - Human Warrior Ally|3|3|Vigilance$Equipment spells you cast cost {1} less to cast for each Ally you control.$At the beginning of combat on your turn, attach up to one target Equipment you control to Sokka.| +Sokka's Sword Training|Avatar: The Last Airbender Eternal|84|C|{1}{W}|Instant - Lesson|||Target creature gets +2/+2 until end of turn.$Create a Clue token.| +Suki, Kyoshi Captain|Avatar: The Last Airbender Eternal|85|R|{2}{W}|Legendary Creature - Human Warrior Ally|3|3|Other Warriors you control get +1/+1.${3}{W}: Attacking Warriors you control gain double strike until end of turn.| +Tale of Momo|Avatar: The Last Airbender Eternal|86|R|{2}{W}|Sorcery|||This spell costs {2} less to cast if a creature left the battlefield under your control this turn.$Search your library and/or graveyard for an Ally creature card, reveal it, and put it into your hand. If you search your library this way, shuffle.| +That's Rough Buddy|Avatar: The Last Airbender Eternal|87|U|{1}{W}|Instant - Lesson|||Put a +1/+1 counter on target creature. Put two +1/+1 counters on that creature instead if a creature left the battlefield under your control this turn.$Draw a card.| +Toucan-Puffin|Avatar: The Last Airbender Eternal|88|C|{2}{W}|Creature - Bird|2|2|Flying$When this creature enters, target creature you control gets +2/+0 until end of turn.| +Baboon Spirit|Avatar: The Last Airbender Eternal|89|R|{2}{U}|Creature - Monkey Spirit|2|4|Whenever another nontoken Spirit you control enters, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."${3}{U}: Exile another target creature you control. Return it to the battlefield under its owner's control at the beginning of the next end step.| +The Blue Spirit|Avatar: The Last Airbender Eternal|90|R|{3}{U}|Legendary Creature - Human Rogue Ally|2|4|You may cast the first creature spell you cast each turn as though it had flash.$Whenever a nontoken creature you control enters during combat, draw a card.| +Chakra Meditation|Avatar: The Last Airbender Eternal|91|R|{2}{U}|Enchantment|||When this enchantment enters, return up to one target instant or sorcery card from your graveyard to your hand.$Whenever you cast an instant or sorcery spell, draw a card. Then discard a card unless there are three or more Lesson cards in your graveyard.| +Dutiful Knowledge Seeker|Avatar: The Last Airbender Eternal|92|U|{2}{U}|Creature - Fox Spirit|2|2|Whenever one or more cards are put into a library from anywhere, put a +1/+1 counter on this creature.${3}: Put target card from a graveyard on the bottom of its owner's library.| Katara, Waterbending Master|Avatar: The Last Airbender Eternal|93|M|{1}{U}|Legendary Creature - Human Warrior Ally|1|3|Whenever you cast a spell during an opponent's turn, you get an experience counter.$Whenever Katara attacks, you may draw a card for each experience counter you have. If you do, discard a card.| +Nightmares and Daydreams|Avatar: The Last Airbender Eternal|94|R|{2}{U}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)$I, II, III -- Until your next turn, whenever you cast an instant or sorcery spell, target player mills cards equal to that spell's mana value.$IV -- Draw a card. If a graveyard has twenty or more cards in it, draw three cards instead.| +Princess Yue|Avatar: The Last Airbender Eternal|95|U|{2}{U}|Legendary Creature - Human Noble Ally|3|2|When Princess Yue dies, if she was a nonland creature, return this card to the battlefield tapped under your control. She's a land named Moon. She gains "{T}: Add {C}."${T}: Scry 2.| +Tui and La, Moon and Ocean|Avatar: The Last Airbender Eternal|96|R|{3}{U}|Legendary Creature - Fish Spirit|3|3|Whenever Tui and La become tapped, draw a card.$Whenever Tui and La become untapped, put a +1/+1 counter on them.| +Unagi's Spray|Avatar: The Last Airbender Eternal|97|C|{U}|Instant|||Target creature gets -4/-0 until end of turn. If you control a Fish, Octopus, Otter, Seal, Serpent, or Whale, draw a card.| +Wan Shi Tong, All-Knowing|Avatar: The Last Airbender Eternal|98|M|{3}{U}{U}|Legendary Creature - Bird Spirit|4|4|Flying$When Wan Shi Tong enters, target nonland permanent's owner puts it into their library second from the top or on the bottom.$Whenever one or more cards are put into a library from anywhere, create two 1/1 colorless Spirit creature tokens with "This token can't block or be blocked by non-Spirit creatures."| +Waterbender's Restoration|Avatar: The Last Airbender Eternal|99|R|{U}{U}|Instant - Lesson|||As an additional cost to cast this spell, waterbend {X}.$Exile X target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step.| +Whirlwind Technique|Avatar: The Last Airbender Eternal|100|U|{4}{U}{U}|Instant - Lesson|||Target player draws two cards, then discards a card.$Airbend up to two target creatures.| +Azula, Ruthless Firebender|Avatar: The Last Airbender Eternal|101|M|{2}{B}|Legendary Creature - Human Noble|3|3|Firebending 1$Whenever Azula attacks, you may discard a card. Then you get an experience counter for each player who discarded a card this turn.${2}{B}: Until end of turn, Azula gets +1/+1 for each experience counter you have and gains menace.| +Dai Li Censor|Avatar: The Last Airbender Eternal|102|C|{1}{B}|Creature - Human Soldier Advisor|2|1|{1}, Sacrifice another creature: This creature gets +2/+2 until end of turn. Activate only once each turn.| +Desperate Plea|Avatar: The Last Airbender Eternal|103|R|{1}{B}|Sorcery - Lesson|||As an additional cost to cast this spell, sacrifice a creature.$Choose one or both --$* Return target creature card from your graveyard to the battlefield if its power is less than or equal to the sacrificed creature's power.$* Destroy target creature.| Fire Lord Ozai|Avatar: The Last Airbender Eternal|104|M|{3}{B}|Legendary Creature - Human Noble|4|4|Whenever Fire Lord Ozai attacks, you may sacrifice another creature. If you do, add an amount of {R} equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end.${6}: Exile the top card of each opponent's library. Until end of turn, you may play one of those cards without paying its mana cost.| +Fire Nation Occupation|Avatar: The Last Airbender Eternal|105|R|{2}{B}|Enchantment|||When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1.$Whenever you cast a spell during an opponent's turn, create a 2/2 red Soldier creature token with firebending 1.| +Fire Nation Salvagers|Avatar: The Last Airbender Eternal|106|R|{3}{B}{B}|Creature - Human Soldier|3|3|Menace$When this creature enters, put a +1/+1 counter on target creature or Vehicle you control.$Whenever one or more creatures you control with counters on them deal combat damage to a player, put target creature or Vehicle card from that player's graveyard onto the battlefield under your control.| +Giant Fly|Avatar: The Last Airbender Eternal|107|C|{2}{B}|Creature - Insect|2|2|Flying$Whenever you sacrifice another permanent, this creature gets +1/+0 until end of turn.| +Lo and Li, Royal Advisors|Avatar: The Last Airbender Eternal|108|R|{2}{B}{B}|Legendary Creature - Human Advisor|3|3|Whenever an opponent discards a card or mills one or more cards, put a +1/+1 counter on each Advisor you control.${2}{U/B}: Target player mills four cards.| +Nyla, Shirshu Sleuth|Avatar: The Last Airbender Eternal|109|R|{4}{B}|Legendary Creature - Mole Beast|4|5|When Nyla enters, exile up to one target creature card from your graveyard. If you do, you lose X life and create X Clue tokens, where X is that card's mana value.$At the beginning of your end step, if you control no Clues, return target card exiled with Nyla to its owner's hand.| +Ruthless Waterbender|Avatar: The Last Airbender Eternal|110|U|{1}{B}|Creature - Human Soldier Ally|1|3|Waterbend {2}: This creature gets +1/+1 until end of turn. Activate only during your turn.| +Scarring Memories|Avatar: The Last Airbender Eternal|111|U|{3}{B}|Sorcery - Lesson|||You may cast this spell as though it had flash if you control an attacking legendary creature.$Target opponent sacrifices a creature of their choice, discards a card, and loses 3 life.| +Avatar Roku, Firebender|Avatar: The Last Airbender Eternal|112|M|{3}{R}{R}{R}|Legendary Creature - Human Avatar|6|6|Whenever a player attacks, add six {R}. Until end of combat, you don't lose this mana as steps end.${R}{R}{R}: Target creature gets +3/+0 until end of turn.| +Chong and Lily, Nomads|Avatar: The Last Airbender Eternal|113|R|{3}{R}|Legendary Creature - Human Bard Ally|3|3|Whenever one or more Bards you control attack, choose one --$* Put a lore counter on each of any number of target Sagas you control.$* Creatures you control get +1/+0 until end of turn for each lore counter among Sagas you control.| +Deer-Dog|Avatar: The Last Airbender Eternal|114|C|{1}{R}|Creature - Elk Dog|1|3|First strike| +Fang, Roku's Companion|Avatar: The Last Airbender Eternal|115|R|{3}{R}{R}|Legendary Creature - Dragon|4|4|Flying$Whenever Fang attacks, another target legendary creature you control gets +X/+0 until end of turn, where X is Fang's power.$When Fang dies, if he wasn't a Spirit, return this card to the battlefield under your control. He's a Spirit in addition to his other types.| +Founding of Omashu|Avatar: The Last Airbender Eternal|116|U|{2}{R}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create two 1/1 white Ally creature tokens.$II -- You may discard a card. If you do,$draw a card.$III -- Creatures you control get +1/+0 until end of turn.| +Frantic Confrontation|Avatar: The Last Airbender Eternal|117|U|{X}{R}|Instant|||Target creature you control gets +X/+0 and gains first strike and trample until end of turn.| +Freedom Fighter Recruit|Avatar: The Last Airbender Eternal|118|C|{1}{R}|Creature - Human Rebel Ally|*|2|Freedom Fighter Recruit's power is equal to the number of creatures you control.| +Iroh, Dragon of the West|Avatar: The Last Airbender Eternal|119|R|{2}{R}{R}|Legendary Creature - Human Noble Ally|4|4|Haste$Mentor$At the beginning of combat on your turn, each creature you control with a counter on it gains firebending 2 until end of turn.| +Longshot, Rebel Bowman|Avatar: The Last Airbender Eternal|120|U|{3}{R}|Legendary Creature - Human Rebel Ally|3|3|Reach$Noncreature spells you cast cost {1} less to cast.$Whenever you cast a noncreature spell, Longshot deals 2 damage to each opponent.| +Lost in Memories|Avatar: The Last Airbender Eternal|121|R|{1}{R}|Enchantment - Aura|||Flash$Enchant creature you control$Enchanted creature gets +1/+1 and has "Whenever this creature deals combat damage to a player, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost."| +Moku, Meandering Drummer|Avatar: The Last Airbender Eternal|122|U|{1}{R}|Legendary Creature - Human Bard Ally|2|2|Whenever you cast a noncreature spell, you may pay {1}. If you do, Moku gets +2/+1 and creatures you control gain haste until end of turn.| +Overwhelming Victory|Avatar: The Last Airbender Eternal|123|R|{4}{R}|Instant - Lesson|||Overwhelming Victory deals 5 damage to target creature. Each creature you control gains trample and gets +X/+0 until end of turn, where X is the amount of excess damage dealt this way.| +Reckless Blaze|Avatar: The Last Airbender Eternal|124|R|{3}{R}{R}|Sorcery - Lesson|||Reckless Blaze deals 5 damage to each creature. Whenever a creature you control dealt damage this way dies this turn, add {R}.| +Smellerbee, Rebel Fighter|Avatar: The Last Airbender Eternal|125|R|{3}{R}|Legendary Creature - Human Rebel Ally|3|3|First strike$Other creatures you control have haste.$Whenever Smellerbee attacks, you may discard your hand. If you do, draw cards equal to the number of attacking creatures.| +Storm of Memories|Avatar: The Last Airbender Eternal|126|R|{2}{R}{R}{R}|Sorcery|||Storm$Exile an instant or sorcery card with mana value 3 or less from your graveyard at random. You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead.| +Zuko, Firebending Master|Avatar: The Last Airbender Eternal|127|M|{1}{R}|Legendary Creature - Human Noble Ally|2|2|First strike$Firebending X, where X is the number of experience counters you have.$Whenever you cast a spell during combat, you get an experience counter.| +Animal Attendant|Avatar: The Last Airbender Eternal|128|U|{1}{G}|Creature - Human Citizen|2|2|{T}: Add one mana of any color. If that mana is spent to cast a non-Human creature spell, that creature enters with an additional +1/+1 counter on it.| +The Art of Tea|Avatar: The Last Airbender Eternal|129|C|{1}{G}|Instant - Lesson|||Put a +1/+1 counter on up to one target creature you control. Create a Food token.| +Avatar Kyoshi, Earthbender|Avatar: The Last Airbender Eternal|130|M|{5}{G}{G}{G}|Legendary Creature - Human Avatar|6|6|During your turn, Avatar Kyoshi has hexproof.$At the beginning of combat on your turn, earthbend 8, then untap that land.| +Bison Whistle|Avatar: The Last Airbender Eternal|131|R|{1}{G}|Artifact|||{1}, {T}: Look at the top card of your library. If it's a Bison card, you may put it onto the battlefield. If it's a creature card, you may reveal it and put it into your hand. Otherwise, you may put it into your graveyard.| +Bosco, Just a Bear|Avatar: The Last Airbender Eternal|132|U|{4}{G}|Legendary Creature - Bear|4|4|When Bosco enters, create a Food token for each legendary creature you control.${2}{G}, Sacrifice a Food: Put two +1/+1 counters on Bosco. He gains trample until end of turn.| +Bumi's Feast Lecture|Avatar: The Last Airbender Eternal|133|U|{1}{G}|Sorcery - Lesson|||Create a Food token. Then earthbend X, where X is twice the number of Foods you control.| The Cabbage Merchant|Avatar: The Last Airbender Eternal|134|R|{2}{G}|Legendary Creature - Human Citizen|2|2|Whenever an opponent casts a noncreature spell, create a Food token.$Whenever a creature deals combat damage to you, sacrifice a Food token.$Tap two untapped Foods you control: Add one mana of any color.| +Cracked Earth Technique|Avatar: The Last Airbender Eternal|135|U|{4}{G}|Sorcery - Lesson|||Earthbend 3, then earthbend 3. You gain 3 life.| +Creeping Crystal Coating|Avatar: The Last Airbender Eternal|136|U|{2}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +0/+3 and has "Whenever this creature attacks, create a Food token."| +Crystalline Armor|Avatar: The Last Airbender Eternal|137|R|{3}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each land you control and has trample.| +Elephant-Mandrill|Avatar: The Last Airbender Eternal|138|U|{2}{G}|Creature - Elephant Monkey|3|2|Reach$When this creature enters, each player creates a Food token.$At the beginning of combat on your turn, this creature gets +1/+1 until end of turn for each artifact your opponents control.| +Hei Bai, Forest Guardian|Avatar: The Last Airbender Eternal|139|M|{3}{G}|Legendary Creature - Bear Spirit|4|4|When Hei Bai enters, reveal cards from the top of your library until you reveal a Shrine card. You may put that card onto the battlefield. Then shuffle.${W}{U}{B}{R}{G}, {T}: For each legendary enchantment you control, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."| +Kyoshi Warrior Exemplars|Avatar: The Last Airbender Eternal|140|U|{3}{G}|Creature - Human Warrior Ally|4|3|Whenever this creature attacks, if you control eight or more lands, creatures you control get +2/+2 until end of turn.| +Master's Guidance|Avatar: The Last Airbender Eternal|141|R|{2}{G}|Enchantment|||Whenever you attack with two or more legendary creatures, put a +1/+1 counter on each of up to two target attacking creatures.$At the beginning of your end step, if you control a creature with power 4 or greater, draw a card.| +Solid Ground|Avatar: The Last Airbender Eternal|142|U|{3}{G}|Enchantment|||When this enchantment enters, earthbend 3.$If one or more +1/+1 counters would be put on a permanent you control, that many plus one +1/+1 counters are put on it instead.| +Tale of Katara and Toph|Avatar: The Last Airbender Eternal|143|R|{2}{G}|Enchantment|||Creatures you control have "Whenever this creature becomes tapped for the first time during each of your turns, put a +1/+1 counter on it."| +Tectonic Split|Avatar: The Last Airbender Eternal|144|R|{4}{G}{G}|Enchantment|||As an additional cost to cast this spell, sacrifice half the lands you control, rounded up.$Hexproof$Lands you control have "{T}: Add three mana of any one color."| +Toph, Earthbending Master|Avatar: The Last Airbender Eternal|145|M|{3}{G}|Legendary Creature - Human Warrior Ally|2|4|Landfall -- Whenever a land you control enters, you get an experience counter.$Whenever you attack, earthbend X, where X is the number of experience counters you have.| +Aang, A Lot to Learn|Avatar: The Last Airbender Eternal|146|U|{2}{G/W}|Legendary Creature - Human Avatar Ally|3|2|Aang has vigilance as long as there's a Lesson card in your graveyard.$Whenever another creature you control dies, put a +1/+1 counter on Aang.| +Hook Swords|Avatar: The Last Airbender Eternal|147|U|{2}{R/W}|Artifact - Equipment|||When this Equipment enters, create a 1/1 white Ally creature token, then attach this Equipment to it.$During your turn, equipped creature gets +1/+1 and has first strike.$Equip {3}| +Katara, Seeking Revenge|Avatar: The Last Airbender Eternal|148|U|{3}{U/B}|Legendary Creature - Human Warrior Ally|3|3|As an additional cost to cast this spell, you may waterbend {2}.$When Katara enters, draw a card, then discard a card unless her additional cost was paid.$Katara gets +1/+1 for each Lesson card in your graveyard.| +Stand United|Avatar: The Last Airbender Eternal|149|C|{1}{G/W}|Instant|||Target creature gets +2/+2 until end of turn. If it's an Ally, scry 2.| +Zuko, Seeking Honor|Avatar: The Last Airbender Eternal|150|U|{2}{B/R}|Legendary Creature - Human Noble|2|2|Firebending 1$Whenever you cast a noncreature spell, Zuko gains first strike until end of turn.$Whenever Zuko deals combat damage to a player, put a +1/+1 counter on him.| +Acrobatic Leap|Avatar: The Last Airbender Eternal|151|C|{W}|Instant|||Target creature gets +1/+3 and gains flying until end of turn. Untap it.| +Cloudshift|Avatar: The Last Airbender Eternal|152|C|{W}|Instant|||Exile target creature you control, then return that card to the battlefield under your control.| +Duelist's Heritage|Avatar: The Last Airbender Eternal|153|R|{2}{W}|Enchantment|||Whenever one or more creatures attack, you may have target attacking creature gain double strike until end of turn.| +Valorous Stance|Avatar: The Last Airbender Eternal|154|U|{1}{W}|Instant|||Choose one --$* Target creature gains indestructible until end of turn.$* Destroy target creature with toughness 4 or greater.| +Brainstorm|Avatar: The Last Airbender Eternal|155|C|{U}|Instant|||Draw three cards, then put two cards from your hand on top of your library in any order.| +Coastal Piracy|Avatar: The Last Airbender Eternal|156|U|{2}{U}{U}|Enchantment|||Whenever a creature you control deals combat damage to an opponent, you may draw a card.| +Consider|Avatar: The Last Airbender Eternal|157|C|{U}|Instant|||Surveil 1.$Draw a card.| +Dramatic Reversal|Avatar: The Last Airbender Eternal|158|C|{1}{U}|Instant|||Untap all nonland permanents you control.| +Frantic Search|Avatar: The Last Airbender Eternal|159|C|{2}{U}|Instant|||Draw two cards, then discard two cards. Untap up to three lands.| +Bastion of Remembrance|Avatar: The Last Airbender Eternal|160|U|{2}{B}|Enchantment|||When this enchantment enters, create a 1/1 white Human Soldier creature token.$Whenever a creature you control dies, each opponent loses 1 life and you gain 1 life.| +Dark Deal|Avatar: The Last Airbender Eternal|161|U|{2}{B}|Sorcery|||Each player discards all the cards in their hand, then draws that many cards minus one.| +Diresight|Avatar: The Last Airbender Eternal|162|C|{2}{B}|Sorcery|||Surveil 2, then draw two cards. You lose 2 life.| +Bolt Bend|Avatar: The Last Airbender Eternal|163|U|{3}{R}|Instant|||This spell costs {3} less to cast if you control a creature with power 4 or greater.$Change the target of target spell or ability with a single target.| +Cathartic Reunion|Avatar: The Last Airbender Eternal|164|C|{1}{R}|Sorcery|||As an additional cost to cast this spell, discard two cards.$Draw three cards.| +Fiery Confluence|Avatar: The Last Airbender Eternal|165|R|{2}{R}{R}|Sorcery|||Choose three. You may choose the same mode more than once.$* Fiery Confluence deals 1 damage to each creature.$* Fiery Confluence deals 2 damage to each opponent.$* Destroy target artifact.| +Fists of Flame|Avatar: The Last Airbender Eternal|166|C|{1}{R}|Instant|||Draw a card. Until end of turn, target creature gains trample and gets +1/+0 for each card you've drawn this turn.| +Descendants' Path|Avatar: The Last Airbender Eternal|167|R|{2}{G}|Enchantment|||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 it without paying its mana cost. If you don't cast it, put it on the bottom of your library.| +Inspiring Call|Avatar: The Last Airbender Eternal|168|U|{2}{G}|Instant|||Draw a card for each creature you control with a +1/+1 counter on it. Those creatures gain indestructible until end of turn.| +Many Partings|Avatar: The Last Airbender Eternal|169|C|{G}|Sorcery|||Search your library for a basic land card, reveal it, put it into your hand, then shuffle. Create a Food token.| +Suspicious Bookcase|Avatar: The Last Airbender Eternal|170|U|{2}|Artifact Creature - Wall|0|4|Defender${3}, {T}: Target creature can't be blocked this turn.| +Aang, Airbending Master|Avatar: The Last Airbender Eternal|171|M|{4}{W}|Legendary Creature - Human Avatar Ally|4|4|When Aang enters, airbend another target creature.$Whenever one or more creatures you control leave the battlefield without dying, you get an experience counter.$At the beginning of your upkeep, create a 1/1 white Ally creature token for each experience counter you have.| +Jet, Rebel Leader|Avatar: The Last Airbender Eternal|172|R|{3}{W}|Legendary Creature - Human Rebel Ally|3|4|Whenever Jet attacks, look at the top five cards of your library. You may put a creature card with mana value 3 or less from among them onto the battlefield tapped and attacking. Put the rest on the bottom of your library in a random order.| +Monk Gyatso|Avatar: The Last Airbender Eternal|173|R|{3}{W}|Legendary Creature - Human Monk|3|3|Whenever another creature you control becomes the target of a spell or ability, you may airbend that creature.| +Sokka, Swordmaster|Avatar: The Last Airbender Eternal|174|M|{2}{W}|Legendary Creature - Human Warrior Ally|3|3|Vigilance$Equipment spells you cast cost {1} less to cast for each Ally you control.$At the beginning of combat on your turn, attach up to one target Equipment you control to Sokka.| +Suki, Kyoshi Captain|Avatar: The Last Airbender Eternal|175|R|{2}{W}|Legendary Creature - Human Warrior Ally|3|3|Other Warriors you control get +1/+1.${3}{W}: Attacking Warriors you control gain double strike until end of turn.| +Tale of Momo|Avatar: The Last Airbender Eternal|176|R|{2}{W}|Sorcery|||This spell costs {2} less to cast if a creature left the battlefield under your control this turn.$Search your library and/or graveyard for an Ally creature card, reveal it, and put it into your hand. If you search your library this way, shuffle.| +Baboon Spirit|Avatar: The Last Airbender Eternal|177|R|{2}{U}|Creature - Monkey Spirit|2|4|Whenever another nontoken Spirit you control enters, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."${3}{U}: Exile another target creature you control. Return it to the battlefield under its owner's control at the beginning of the next end step.| +The Blue Spirit|Avatar: The Last Airbender Eternal|178|R|{3}{U}|Legendary Creature - Human Rogue Ally|2|4|You may cast the first creature spell you cast each turn as though it had flash.$Whenever a nontoken creature you control enters during combat, draw a card.| +Chakra Meditation|Avatar: The Last Airbender Eternal|179|R|{2}{U}|Enchantment|||When this enchantment enters, return up to one target instant or sorcery card from your graveyard to your hand.$Whenever you cast an instant or sorcery spell, draw a card. Then discard a card unless there are three or more Lesson cards in your graveyard.| +Katara, Waterbending Master|Avatar: The Last Airbender Eternal|180|M|{1}{U}|Legendary Creature - Human Warrior Ally|1|3|Whenever you cast a spell during an opponent's turn, you get an experience counter.$Whenever Katara attacks, you may draw a card for each experience counter you have. If you do, discard a card.| +Tui and La, Moon and Ocean|Avatar: The Last Airbender Eternal|181|R|{3}{U}|Legendary Creature - Fish Spirit|3|3|Whenever Tui and La become tapped, draw a card.$Whenever Tui and La become untapped, put a +1/+1 counter on them.| +Wan Shi Tong, All-Knowing|Avatar: The Last Airbender Eternal|182|M|{3}{U}{U}|Legendary Creature - Bird Spirit|4|4|Flying$When Wan Shi Tong enters, target nonland permanent's owner puts it into their library second from the top or on the bottom.$Whenever one or more cards are put into a library from anywhere, create two 1/1 colorless Spirit creature tokens with "This token can't block or be blocked by non-Spirit creatures."| +Waterbender's Restoration|Avatar: The Last Airbender Eternal|183|R|{U}{U}|Instant - Lesson|||As an additional cost to cast this spell, waterbend {X}.$Exile X target creatures you control. Return those cards to the battlefield under their owner's control at the beginning of the next end step.| +Azula, Ruthless Firebender|Avatar: The Last Airbender Eternal|184|M|{2}{B}|Legendary Creature - Human Noble|3|3|Firebending 1$Whenever Azula attacks, you may discard a card. Then you get an experience counter for each player who discarded a card this turn.${2}{B}: Until end of turn, Azula gets +1/+1 for each experience counter you have and gains menace.| +Desperate Plea|Avatar: The Last Airbender Eternal|185|R|{1}{B}|Sorcery - Lesson|||As an additional cost to cast this spell, sacrifice a creature.$Choose one or both --$* Return target creature card from your graveyard to the battlefield if its power is less than or equal to the sacrificed creature's power.$* Destroy target creature.| +Fire Lord Ozai|Avatar: The Last Airbender Eternal|186|M|{3}{B}|Legendary Creature - Human Noble|4|4|Whenever Fire Lord Ozai attacks, you may sacrifice another creature. If you do, add an amount of {R} equal to the sacrificed creature's power. Until end of combat, you don't lose this mana as steps end.${6}: Exile the top card of each opponent's library. Until end of turn, you may play one of those cards without paying its mana cost.| +Fire Nation Occupation|Avatar: The Last Airbender Eternal|187|R|{2}{B}|Enchantment|||When this enchantment enters, create a 2/2 red Soldier creature token with firebending 1.$Whenever you cast a spell during an opponent's turn, create a 2/2 red Soldier creature token with firebending 1.| +Fire Nation Salvagers|Avatar: The Last Airbender Eternal|188|R|{3}{B}{B}|Creature - Human Soldier|3|3|Menace$When this creature enters, put a +1/+1 counter on target creature or Vehicle you control.$Whenever one or more creatures you control with counters on them deal combat damage to a player, put target creature or Vehicle card from that player's graveyard onto the battlefield under your control.| +Lo and Li, Royal Advisors|Avatar: The Last Airbender Eternal|189|R|{2}{B}{B}|Legendary Creature - Human Advisor|3|3|Whenever an opponent discards a card or mills one or more cards, put a +1/+1 counter on each Advisor you control.${2}{U/B}: Target player mills four cards.| +Nyla, Shirshu Sleuth|Avatar: The Last Airbender Eternal|190|R|{4}{B}|Legendary Creature - Mole Beast|4|5|When Nyla enters, exile up to one target creature card from your graveyard. If you do, you lose X life and create X Clue tokens, where X is that card's mana value.$At the beginning of your end step, if you control no Clues, return target card exiled with Nyla to its owner's hand.| +Avatar Roku, Firebender|Avatar: The Last Airbender Eternal|191|M|{3}{R}{R}{R}|Legendary Creature - Human Avatar|6|6|Whenever a player attacks, add six {R}. Until end of combat, you don't lose this mana as steps end.${R}{R}{R}: Target creature gets +3/+0 until end of turn.| +Chong and Lily, Nomads|Avatar: The Last Airbender Eternal|192|R|{3}{R}|Legendary Creature - Human Bard Ally|3|3|Whenever one or more Bards you control attack, choose one --$* Put a lore counter on each of any number of target Sagas you control.$* Creatures you control get +1/+0 until end of turn for each lore counter among Sagas you control.| +Fang, Roku's Companion|Avatar: The Last Airbender Eternal|193|R|{3}{R}{R}|Legendary Creature - Dragon|4|4|Flying$Whenever Fang attacks, another target legendary creature you control gets +X/+0 until end of turn, where X is Fang's power.$When Fang dies, if he wasn't a Spirit, return this card to the battlefield under your control. He's a Spirit in addition to his other types.| +Iroh, Dragon of the West|Avatar: The Last Airbender Eternal|194|R|{2}{R}{R}|Legendary Creature - Human Noble Ally|4|4|Haste$Mentor$At the beginning of combat on your turn, each creature you control with a counter on it gains firebending 2 until end of turn.| +Lost in Memories|Avatar: The Last Airbender Eternal|195|R|{1}{R}|Enchantment - Aura|||Flash$Enchant creature you control$Enchanted creature gets +1/+1 and has "Whenever this creature deals combat damage to a player, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost."| +Overwhelming Victory|Avatar: The Last Airbender Eternal|196|R|{4}{R}|Instant - Lesson|||Overwhelming Victory deals 5 damage to target creature. Each creature you control gains trample and gets +X/+0 until end of turn, where X is the amount of excess damage dealt this way.| +Reckless Blaze|Avatar: The Last Airbender Eternal|197|R|{3}{R}{R}|Sorcery - Lesson|||Reckless Blaze deals 5 damage to each creature. Whenever a creature you control dealt damage this way dies this turn, add {R}.| +Smellerbee, Rebel Fighter|Avatar: The Last Airbender Eternal|198|R|{3}{R}|Legendary Creature - Human Rebel Ally|3|3|First strike$Other creatures you control have haste.$Whenever Smellerbee attacks, you may discard your hand. If you do, draw cards equal to the number of attacking creatures.| +Storm of Memories|Avatar: The Last Airbender Eternal|199|R|{2}{R}{R}{R}|Sorcery|||Storm$Exile an instant or sorcery card with mana value 3 or less from your graveyard at random. You may cast it without paying its mana cost. If that spell would be put into a graveyard, exile it instead.| +Zuko, Firebending Master|Avatar: The Last Airbender Eternal|200|M|{1}{R}|Legendary Creature - Human Noble Ally|2|2|First strike$Firebending X, where X is the number of experience counters you have.$Whenever you cast a spell during combat, you get an experience counter.| +Avatar Kyoshi, Earthbender|Avatar: The Last Airbender Eternal|201|M|{5}{G}{G}{G}|Legendary Creature - Human Avatar|6|6|During your turn, Avatar Kyoshi has hexproof.$At the beginning of combat on your turn, earthbend 8, then untap that land.| +Bison Whistle|Avatar: The Last Airbender Eternal|202|R|{1}{G}|Artifact|||{1}, {T}: Look at the top card of your library. If it's a Bison card, you may put it onto the battlefield. If it's a creature card, you may reveal it and put it into your hand. Otherwise, you may put it into your graveyard.| +The Cabbage Merchant|Avatar: The Last Airbender Eternal|203|R|{2}{G}|Legendary Creature - Human Citizen|2|2|Whenever an opponent casts a noncreature spell, create a Food token.$Whenever a creature deals combat damage to you, sacrifice a Food token.$Tap two untapped Foods you control: Add one mana of any color.| +Crystalline Armor|Avatar: The Last Airbender Eternal|204|R|{3}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each land you control and has trample.| +Hei Bai, Forest Guardian|Avatar: The Last Airbender Eternal|205|M|{3}{G}|Legendary Creature - Bear Spirit|4|4|When Hei Bai enters, reveal cards from the top of your library until you reveal a Shrine card. You may put that card onto the battlefield. Then shuffle.${W}{U}{B}{R}{G}, {T}: For each legendary enchantment you control, create a 1/1 colorless Spirit creature token with "This token can't block or be blocked by non-Spirit creatures."| +Master's Guidance|Avatar: The Last Airbender Eternal|206|R|{2}{G}|Enchantment|||Whenever you attack with two or more legendary creatures, put a +1/+1 counter on each of up to two target attacking creatures.$At the beginning of your end step, if you control a creature with power 4 or greater, draw a card.| +Tale of Katara and Toph|Avatar: The Last Airbender Eternal|207|R|{2}{G}|Enchantment|||Creatures you control have "Whenever this creature becomes tapped for the first time during each of your turns, put a +1/+1 counter on it."| +Tectonic Split|Avatar: The Last Airbender Eternal|208|R|{4}{G}{G}|Enchantment|||As an additional cost to cast this spell, sacrifice half the lands you control, rounded up.$Hexproof$Lands you control have "{T}: Add three mana of any one color."| +Toph, Earthbending Master|Avatar: The Last Airbender Eternal|209|M|{3}{G}|Legendary Creature - Human Warrior Ally|2|4|Landfall -- Whenever a land you control enters, you get an experience counter.$Whenever you attack, earthbend X, where X is the number of experience counters you have.| Aang, Air Nomad|Avatar: The Last Airbender Eternal|210|R|{3}{W}{W}|Legendary Creature - Human Avatar Ally|5|4|Flying$Vigilance$Other creatures you control have vigilance.| Aang's Defense|Avatar: The Last Airbender Eternal|211|C|{W}|Instant|||Target blocking creature you control gets +2/+2 until end of turn.$Draw a card.| Aardvark Sloth|Avatar: The Last Airbender Eternal|212|C|{3}{W}|Creature - Sloth Beast|3|3|Lifelink| @@ -60275,12 +60805,28 @@ Plains|Avatar: The Last Airbender Eternal|301|C||Basic Land - Plains|||({T}: Add Plains|Avatar: The Last Airbender Eternal|302|C||Basic Land - Plains|||({T}: Add {W}.)| Plains|Avatar: The Last Airbender Eternal|303|C||Basic Land - Plains|||({T}: Add {W}.)| Plains|Avatar: The Last Airbender Eternal|304|C||Basic Land - Plains|||({T}: Add {W}.)| +Enlightened Tutor|Avatar: The Last Airbender Eternal|305|R|{W}|Instant|||Search your library for an artifact or enchantment card, reveal it, then shuffle and put that card on top.| +Flawless Maneuver|Avatar: The Last Airbender Eternal|306|R|{2}{W}|Instant|||If you control a commander, you may cast this spell without paying its mana cost.$Creatures you control gain indestructible until end of turn.| +Fierce Guardianship|Avatar: The Last Airbender Eternal|307|R|{2}{U}|Instant|||If you control a commander, you may cast this spell without paying its mana cost.$Counter target noncreature spell.| +Mystical Tutor|Avatar: The Last Airbender Eternal|308|R|{U}|Instant|||Search your library for an instant or sorcery card, reveal it, then shuffle and put that card on top.| +Deadly Rollick|Avatar: The Last Airbender Eternal|309|R|{3}{B}|Instant|||If you control a commander, you may cast this spell without paying its mana cost.$Exile target creature.| +Entomb|Avatar: The Last Airbender Eternal|310|R|{B}|Instant|||Search your library for a card, put that card into your graveyard, then shuffle.| +Deflecting Swat|Avatar: The Last Airbender Eternal|311|R|{2}{R}|Instant|||If you control a commander, you may cast this spell without paying its mana cost.$You may choose new targets for target spell or ability.| +Gamble|Avatar: The Last Airbender Eternal|312|R|{R}|Sorcery|||Search your library for a card, put that card into your hand, discard a card at random, then shuffle.| +Obscuring Haze|Avatar: The Last Airbender Eternal|313|R|{2}{G}|Instant|||If you control a commander, you may cast this spell without paying its mana cost.$Prevent all damage that would be dealt this turn by creatures your opponents control.| +Worldly Tutor|Avatar: The Last Airbender Eternal|314|R|{G}|Instant|||Search your library for a creature card, reveal it, then shuffle and put the card on top.| +Arcane Signet|Avatar: The Last Airbender Eternal|315|R|{2}|Artifact|||{T}: Add one mana of any color in your commander's color identity.| +Sol Ring|Avatar: The Last Airbender Eternal|316|R|{1}|Artifact|||{T}: Add {C}{C}.| +Swiftfoot Boots|Avatar: The Last Airbender Eternal|317|R|{2}|Artifact - Equipment|||Equipped creature has hexproof and haste.$Equip {1}| Eirdu, Carrier of Dawn|Lorwyn Eclipsed|13|M|{3}{W}{W}|Legendary Creature - Elemental God|5|5|Flying, lifelink$Creature spells you cast have convoke.$At the beginning of your first main phase, you may pay {B}. If you do, transform Eirdu.| Isilu, Carrier of Twilight|Lorwyn Eclipsed|13|M||Legendary Creature - Elemental God|5|5|Flying, lifelink$Each other nontoken creature you control has persist.$At the beginning of your first main phase, you may pay {W}. If you do, transform Isilu.| Morningtide's Light|Lorwyn Eclipsed|27|M|{3}{W}|Sorcery|||Exile any number of target creatures. At the beginning of the next end step, return those cards to the battlefield tapped under their owners' control.$Until your next turn, prevent all damage that would be dealt to you.$Exile Morningtide's Light.| Sygg, Wanderwine Wisdom|Lorwyn Eclipsed|76|R|{1}{U}|Legendary Creature - Merfolk Wizard|2|2|Sygg can't be blocked.$Whenever this creature enters or transforms into Sygg, Wanderwine Wisdom, target creature gains "Whenever this creature deals combat damage to a player or planeswalker, draw a card" until end of turn.$At the beginning of your first main phase, you may pay {W}. If you do, transform Sygg.| Sygg, Wanderbrine Shield|Lorwyn Eclipsed|76|R||Legendary Creature - Merfolk Rogue|2|2|Sygg can't be blocked.$Whenever this creature transforms into Sygg, Wanderbrine Shield, target creature you control gains protection from each color until your next turn.$At the beginning of your first main phase, you may pay {U}. If you do, transform Sygg.| +Unexpected Assistance|Lorwyn Eclipsed|80|C|{3}{U}{U}|Instant|||Convoke$Draw three cards, then discard a card.| Bitterbloom Bearer|Lorwyn Eclipsed|88|M|{B}{B}|Creature - Faerie Rogue|1|1|Flash$Flying$At the beginning of your upkeep, you lose 1 life and create a 1/1 blue and black Faerie creature token with flying.| +Dose of Dawnglow|Lorwyn Eclipsed|100|U|{4}{B}|Instant|||Return target creature card from your graveyard to the battlefield. Then if it isn't your main phase, blight 2.| +Perfect Intimidation|Lorwyn Eclipsed|115|U|{3}{B}|Sorcery|||Choose one or both --$* Target opponent exiles two cards from their hand.$* Remove all counters from target creature.| Ashling, Rekindled|Lorwyn Eclipsed|124|R|{1}{R}|Legendary Creature - Elemental Sorcerer|1|3|Whenever this creature enters or transforms into Ashling, Rekindled, you may discard a card. If you do, draw a card.$At the beginning of your first main phase, you may pay {U}. If you do, transform Ashling.| Ashling, Rimebound|Lorwyn Eclipsed|124|R||Legendary Creature - Elemental Wizard|1|3|Whenever this creature transforms into Ashling, Rimebound and at the beginning of your first main phase, add two mana of any one color. Spend this mana only to cast spells with mana value 4 or greater.$At the beginning of your first main phase, you may pay {R}. If you do, transform Ashling.| Formidable Speaker|Lorwyn Eclipsed|176|R|{2}{G}|Creature - Elf Druid|2|4|When this creature enters, you may discard a card. If you do, search your library for a creature card, reveal it, put it into your hand, then shuffle.${1}, {T}: Untap another target permanent.| @@ -60289,6 +60835,8 @@ Ashling's Command|Lorwyn Eclipsed|205|R|{3}{U}{R}|Kindred Instant - Elemental||| Deceit|Lorwyn Eclipsed|212|M|{4}{U/B}{U/B}|Creature - Elemental Incarnation|5|5|When this creature enters, if {U}{U} was spent to cast it, return up to one other target nonland permanent to its owner's hand.$When this creature enters, if {B}{B} was spent to cast it, target opponent reveals their hand. You choose a nonland card from it. That player discards that card.$Evoke {U/B}{U/B}| Emptiness|Lorwyn Eclipsed|222|M|{4}{W/B}{W/B}|Creature - Elemental Incarnation|3|5|When this creature enters, if {W}{W} was spent to cast it, return target creature card with mana value 3 or less from your graveyard to the battlefield.$When this creature enters, if {B}{B} was spent to cast it, put three -1/-1 counters on up to one target creature.$Evoke {W/B}{W/B}| Figure of Fable|Lorwyn Eclipsed|224|R|{G/W}|Creature - Kithkin|1|1|{G/W}: This creature becomes a Kithkin Scout with base power and toughness 2/3.${1}{G/W}{G/W}: If this creature is a Scout, it becomes a Kithkin Soldier with base power and toughness 4/5.${3}{G/W}{G/W}{G/W}: If this creature is a Soldier, it becomes a Kithkin Avatar with base power and toughness 7/8 and protection from each of your opponents.| +High Perfect Morcant|Lorwyn Eclipsed|229|R|{2}{B}{G}|Legendary Creature - Elf Noble|4|4|Whenever High Perfect Morcant or another Elf you control enters, each opponent blights 1.$Tap three untapped Elves you control: Proliferate. Activate only as a sorcery.| +Kirol, Attentive First-Year|Lorwyn Eclipsed|231|R|{1}{R/W}{R/W}|Legendary Creature - Vampire Cleric|3|3|Tap two untapped creatures you control: Copy target triggered ability you control. You may choose new targets for the copy. Activate only once each turn.| Blood Crypt|Lorwyn Eclipsed|262|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Hallowed Fountain|Lorwyn Eclipsed|265|R||Land - Plains Island|||({T}: Add {W} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Overgrown Tomb|Lorwyn Eclipsed|266|R||Land - Swamp Forest|||({T}: Add {B} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| @@ -60307,13 +60855,20 @@ Bitterbloom Bearer|Lorwyn Eclipsed|310|M|{B}{B}|Creature - Faerie Rogue|1|1|Flas Mutable Explorer|Lorwyn Eclipsed|327|R|{2}{G}|Creature - Shapeshifter|1|1|Changeling$When this creature enters, create a tapped Mutavault token.| Ashling's Command|Lorwyn Eclipsed|330|R|{3}{U}{R}|Kindred Instant - Elemental|||Choose two --$* Create a token that's a copy of target Elemental you control.$* Target player draws two cards.$* Ashling's Command deals 2 damage to each creature target player controls.$* Target player creates two Treasure tokens.| Hallowed Fountain|Lorwyn Eclipsed|347|R||Land - Plains Island|||({T}: Add {W} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Hallowed Fountain|Lorwyn Eclipsed|347b|R||Land - Plains Island|||({T}: Add {W} or {U}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Steam Vents|Lorwyn Eclipsed|348|R||Land - Island Mountain|||({T}: Add {U} or {R}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Steam Vents|Lorwyn Eclipsed|348b|R||Land - Island Mountain|||({T}: Add {U} or {R}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Blood Crypt|Lorwyn Eclipsed|349|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Blood Crypt|Lorwyn Eclipsed|349b|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Overgrown Tomb|Lorwyn Eclipsed|350|R||Land - Swamp Forest|||({T}: Add {B} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Overgrown Tomb|Lorwyn Eclipsed|350b|R||Land - Swamp Forest|||({T}: Add {B} or {G}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Temple Garden|Lorwyn Eclipsed|351|R||Land - Forest Plains|||({T}: Add {G} or {W}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| +Temple Garden|Lorwyn Eclipsed|351b|R||Land - Forest Plains|||({T}: Add {G} or {W}.)$As this land enters, you may pay 2 life. If you don't, it enters tapped.| Bitterbloom Bearer|Lorwyn Eclipsed|352|M|{B}{B}|Creature - Faerie Rogue|1|1|Flash$Flying$At the beginning of your upkeep, you lose 1 life and create a 1/1 blue and black Faerie creature token with flying.| Formidable Speaker|Lorwyn Eclipsed|366|R|{2}{G}|Creature - Elf Druid|2|4|When this creature enters, you may discard a card. If you do, search your library for a creature card, reveal it, put it into your hand, then shuffle.${1}, {T}: Untap another target permanent.| Figure of Fable|Lorwyn Eclipsed|372|R|{G/W}|Creature - Kithkin|1|1|{G/W}: This creature becomes a Kithkin Scout with base power and toughness 2/3.${1}{G/W}{G/W}: If this creature is a Scout, it becomes a Kithkin Soldier with base power and toughness 4/5.${3}{G/W}{G/W}{G/W}: If this creature is a Soldier, it becomes a Kithkin Avatar with base power and toughness 7/8 and protection from each of your opponents.| +High Perfect Morcant|Lorwyn Eclipsed|373|R|{2}{B}{G}|Legendary Creature - Elf Noble|4|4|Whenever High Perfect Morcant or another Elf you control enters, each opponent blights 1.$Tap three untapped Elves you control: Proliferate. Activate only as a sorcery.| +Kirol, Attentive First-Year|Lorwyn Eclipsed|374|R|{1}{R/W}{R/W}|Legendary Creature - Vampire Cleric|3|3|Tap two untapped creatures you control: Copy target triggered ability you control. You may choose new targets for the copy. Activate only once each turn.| Greymond, Avacyn's Stalwart|Secret Lair Drop|143|M|{2}{W}{W}|Legendary Creature - Human Soldier|3|4|As Greymond, Avacyn's Stalwart enters, choose two abilities from among first strike, vigilance, and lifelink.$Humans you control have each of the chosen abilities.$As long as you control four or more Humans, Humans you control get +2/+2.| Hansk, Slayer Zealot|Secret Lair Drop|144|M|{2}{R}{G}|Legendary Creature - Human Archer|4|4|At the beginning of your upkeep, target opponent creates three Walker tokens.${T}: Hansk, Slayer Zealot deals 2 damage to target creature.$Whenever a Zombie an opponent controls dies, draw a card.| Gregor, Shrewd Magistrate|Secret Lair Drop|145|M|{1}{W}{U}|Legendary Creature - Human Advisor|1|3|Skulk$Whenever Gregor, Shrewd Magistrate deals combat damage to a player, draw cards equal to its power.| @@ -60382,3 +60937,61 @@ Kratos, Stoic Father|Secret Lair Drop|2213|M|{2}{R}{W}|Legendary Creature - God Nathan Drake, Treasure Hunter|Secret Lair Drop|2216|M|{U}{B}{R}|Legendary Creature - Human Rogue|3|2|First strike$You may spend mana as though it were mana of any color to cast spells you don't own or to activate abilities of permanents you control but don't own.$Whenever Nathan Drake attacks, exile the top card of each player's library. You may cast a spell from among those cards.| Aloy, Savior of Meridian|Secret Lair Drop|2221|M|{3}{G}{U}|Legendary Creature - Human Warrior|3|5|Vigilance, reach$In You, All Things Are Possible -- Whenever one or more artifact creatures you control attack, discover X, where X is the greatest power among them.| Jin Sakai, Ghost of Tsushima|Secret Lair Drop|2226|M|{1}{W}{U}{B}|Legendary Creature - Human Samurai|2|4|Whenever Jin Sakai deals combat damage to a player, draw a card.$Whenever a creature you control attacks a player, if no other creatures are attacking that player, choose one --$* Standoff -- It gains double strike until end of turn.$* Ghost -- It can't be blocked this turn.| +Leonardo, Sewer Samurai|Teenage Mutant Ninja Turtles|17|M|{3}{W}|Legendary Creature - Mutant Ninja Turtle Samurai|3|3|Sneak {2}{W}{W}$Double strike$During your turn, you may cast creature spells with power or toughness 1 or less from your graveyard. If you cast a spell this way, that creature enters with a finality counter on it.| +Turtles Forever|Teenage Mutant Ninja Turtles|27|R|{3}{W}|Instant|||Search your library and/or outside the game for exactly four legendary creature cards you own with different names, then reveal those cards. An opponent chooses two of them. Put the chosen cards into your hand and shuffle the rest into your library.| +April O'Neil, Hacktivist|Teenage Mutant Ninja Turtles|29|R|{3}{U}|Legendary Creature - Human Scientist|1|5|At the beginning of your end step, draw a card for each card type among spells you've cast this turn.| +Krang, Master Mind|Teenage Mutant Ninja Turtles|43|R|{6}{U}{U}|Legendary Artifact Creature - Utrom Warrior|1|4|Affinity for artifacts$When Krang enters, if you have fewer than four cards in hand, draw cards equal to the difference.$Krang gets +1/+0 for each other artifact you control.| +Super Shredder|Teenage Mutant Ninja Turtles|83|M|{1}{B}|Legendary Creature - Mutant Ninja Human|1|1|Menace$Whenever another permanent leaves the battlefield, put a +1/+1 counter on Super Shredder.| +Casey Jones, Jury-Rig Justiciar|Teenage Mutant Ninja Turtles|87|U|{1}{R}|Legendary Creature Human Berserker|2|1|Haste$When Casey Jones enters, 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 a random order.| +Raphael's Technique|Teenage Mutant Ninja Turtles|105|R|{4}{R}{R}|Instant|||Sneak {2}{R}$Each player may discard their hand and draw seven cards.| +Bebop & Rocksteady|Teenage Mutant Ninja Turtles|140|R|{1}{B/G}{B/G}|Legendary Creature - Boar Rhino Mutant|7|5|Whenever Bebop & Rocksteady attack or block, sacrifice a permanent unless you discard a card.| +Plains|Teenage Mutant Ninja Turtles|253|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Teenage Mutant Ninja Turtles|254|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Teenage Mutant Ninja Turtles|255|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Teenage Mutant Ninja Turtles|256|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Teenage Mutant Ninja Turtles|257|C||Basic Land - Forest|||({T}: Add {G}.)| +Turtles Forever|Teenage Mutant Ninja Turtles|261|R|{3}{W}|Instant|||Search your library and/or outside the game for exactly four legendary creature cards you own with different names, then reveal those cards. An opponent chooses two of them. Put the chosen cards into your hand and shuffle the rest into your library.| +Leonardo, Sewer Samurai|Teenage Mutant Ninja Turtles|301|M|{3}{W}|Legendary Creature - Mutant Ninja Turtle Samurai|3|3|Sneak {2}{W}{W}$Double strike$During your turn, you may cast creature spells with power or toughness 1 or less from your graveyard. If you cast a spell this way, that creature enters with a finality counter on it.| +Plains|Teenage Mutant Ninja Turtles|310|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Teenage Mutant Ninja Turtles|311|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Teenage Mutant Ninja Turtles|312|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Teenage Mutant Ninja Turtles|313|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Teenage Mutant Ninja Turtles|314|C||Basic Land - Forest|||({T}: Add {G}.)| +Leonardo, the Balance|Teenage Mutant Ninja Turtles Eternal|1|M|{3}{W}|Legendary Creature - Mutant Ninja Turtle|3|3|Whenever a token you control enters, you may put a +1/+1 counter on each creature you control. Do this only once each turn.${W}{U}{B}{R}{G}: Creatures you control gain menace, trample, and lifelink until end of turn.$Partner--Character select| +Donatello, the Brains|Teenage Mutant Ninja Turtles Eternal|2|M|{2}{U}|Legendary Creature - Mutant Ninja Turtle|2|4|If one or more tokens would be created under your control, those tokens plus a Mutagen token are created instead.$Partner--Character select| +Splinter, the Mentor|Teenage Mutant Ninja Turtles Eternal|3|M|{1}{B}|Legendary Creature - Mutant Ninja Rat|2|2|Menace$Whenever Splinter or another nontoken creature you control leaves the battlefield, create a Mutagen token.$Partner--Character select| +Raphael, the Muscle|Teenage Mutant Ninja Turtles Eternal|4|M|{4}{R}|Legendary Creature - Mutant Ninja Turtle|4|4|Double all damage that creatures you control with counters on them would deal.$When Raphael enters, create a Mutagen token.$Partner--Character select| +Michelangelo, the Heart|Teenage Mutant Ninja Turtles Eternal|5|M|{1}{G}|Legendary Creature - Mutant Ninja Turtle|2|1|Trample$Raid -- At the beginning of your second main phase, if you attacked this turn, put a +1/+1 counter on target creature and create a Food token.$Partner--Character select| +Heroes in a Half Shell|Teenage Mutant Ninja Turtles Eternal|6|M|{W}{U}{B}{R}{G}|Legendary Creature - Mutant Ninja Turtle|5|5|Vigilance, menace, trample, haste$Whenever one or more Mutants, Ninjas, and/or Turtles you control deal combat damage to a player, put a +1/+1 counter on each of those creatures and draw a card.| +Leonardo, Worldly Warrior|Teenage Mutant Ninja Turtles Eternal|101|M|{7}{W}|Legendary Creature - Mutant Ninja Turtle|5|5|This spell costs {1} less to cast for each creature you control.$Double strike| +Donatello, Rad Scientist|Teenage Mutant Ninja Turtles Eternal|109|M|{5}{U}|Legendary Creature - Mutant Ninja Turtle|5|6|Vigilance$When Donatello enters, tap up to three target creatures your opponents control. Put a stun counter on each of them.| +Donnie & April, Adorkable Duo|Teenage Mutant Ninja Turtles Eternal|111|R|{4}{U}|Legendary Creature - Mutant Ninja Human Turtle|3|3|When Donnie & April enter, choose one or both. Each mode must target a different player.$* Target player draws two cards.$* Target player returns an artifact, instant, or sorcery card from their graveyard to their hand.| +Raphael, Tag Team Tough|Teenage Mutant Ninja Turtles Eternal|118|M|{4}{R}{R}|Legendary Creature - Mutant Ninja Turtle|5|6|Menace$Whenever Raphael deals combat damage to a player for the first time each turn, untap all attacking creatures. After this combat phase, there is an additional combat phase.| +Michelangelo, On the Scene|Teenage Mutant Ninja Turtles Eternal|124|M|{4}{G}{G}|Legendary Creature - Mutant Ninja Turtle|2|2|Trample$Michelangelo enters with a +1/+1 counter on him for each land you control.$When Michelangelo dies, return this card to your hand.| +Dark Ritual|Teenage Mutant Ninja Turtles Eternal|131|M|{B}|Instant|||Add {B}{B}{B}.| +Captain America, Super-Soldier|Marvel Super Heroes|9|M|{1}{W}{W}|Legendary Creature - Human Soldier Hero|3|2|First strike$Captain America enters with a shield counter on him.$As long as Captain America has a shield counter on him, you and other Heroes you control have hexproof.| +The Sentry, Golden Guardian|Marvel Super Heroes|35|R|{3}{W}|Legendary Creature - Human Hero|5|5|Flying, vigilance, indestructible$When The Sentry enters, target opponent creates The Void, a legendary 5/5 black Horror Villain creature token with flying, indestructible, and "The Void attacks each combat if able."| +Attuma, Atlantean Warlord|Marvel Super Heroes|47|U|{2}{U}{U}|Legendary Creature - Merfolk Warrior Villain|3|4|Other Merfolk you control get +1/+1.$Whenever one or more Merfolk you control attack a player, draw a card.| +Bruce Banner|Marvel Super Heroes|49|M|{U}|Legendary Creature - Human Scientist Hero|1|1|{X}{X}, {T}: Draw X cards. Activate only as a sorcery.${2}{R}{R}{G}{G}: Transform Bruce Banner. Activate only as a sorcery.| +The Incredible Hulk|Marvel Super Heroes|49|M|{2}{R}{R}{G}{G}|1/1 Creature|8|8|Reach, trample$Enrage -- Whenever The Incredible Hulk is dealt damage, put a +1/+1 counter on him. If he's attacking, untap him and there is an additional combat phase after this phase.| +Namor the Sub-Mariner|Marvel Super Heroes|69|M|{1}{U}{U}|Legendary Creature - Mutant Merfolk Villain|*|4|Flying$Namor's power is equal to the number of Merfolk you control.$Whenever you cast a noncreature spell with one or more blue mana symbols in its mana cost, create that many 1/1 blue Merfolk creature tokens.| +Baron Helmut Zemo|Marvel Super Heroes|87|R|{B}{B}{B}|Legendary Creature - Human Noble Villain|3|3|Whenever you cast a black spell from your hand, Baron Helmut Zemo connives.$Boast -- Exile any number of black cards from your graveyard with fifteen or more black mana symbols among their mana costs: Copy those exiled cards. You may cast up to three of the copies without paying their mana costs.| +Doctor Doom|Marvel Super Heroes|95|M|{4}{B}{B}|Legendary Creature - Human Scientist Villain|3|3|When Doctor Doom enters, create two 3/3 colorless Robot Villain artifact creature tokens named Doombot.$As long as you control an artifact creature or a Plan, Doctor Doom has indestructible.$At the beginning of your end step, you draw a card and lose 1 life.| +Doom Reigns Supreme|Marvel Super Heroes|96|R|{1}{B}|Enchantment - Plan|||Whenever a Villain you control enters, each opponent loses 1 life and you gain 1 life. Put a plan counter on this enchantment.$When the fifth plan counter is put on this enchantment, sacrifice it. When you do, target opponent exiles the top five cards of their library. You may cast up to two spells from among the exiled cards without paying their mana costs.| +Super-Skrull|Marvel Super Heroes|115|R|{1}{B}{B}{B}|Legendary Creature - Skrull Shapeshifter Villain|4|5|Flying${2}{W}: Create a 0/4 colorless Wall creature token with defender.${3}{G}: Super-Skrull gets +4/+4 until end of turn.${4}{R}: Super-Skrull deals 4 damage to target creature.${5}{U}: Target player draws four cards.| +Thunderbolts Conspiracy|Marvel Super Heroes|117|R|{3}{B}|Enchantment|||Flash$Whenever a Villain you control dies, return it to the battlefield under its owner's control with a finality counter on it. That creature is a Hero in addition to its other types.| +Quicksilver, Brash Blur|Marvel Super Heroes|148|R|{R}|Legendary Creature - Mutant Hero|1|1|If Quicksilver, Brash Blur is in your opening hand, you may begin the game with him on the battlefield.$Haste$Power-up -- {4}{R}: Put a +1/+1 counter and a double strike counter on Quicksilver.| +World War Hulk|Marvel Super Heroes|197|R|{3}{G}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- The next red or green creature spell you cast this turn can be cast without paying its mana cost.$II -- Put three +1/+1 counters on target creature you control.$III -- Choose target creature you control. Until end of turn, double its power and toughness and it gains trample.| +The Coming of Galactus|Marvel Super Heroes|212|M|{2}{B}{B}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)$I -- Destroy up to one target nonland permanent.$II, III -- Each opponent loses 2 life.$IV -- Create Galactus, a legendary 16/16 black Elder alien creature token with flying, trample, and "Whenever Galactus attacks, destroy target land."| +Moon Girl and Devil Dinosaur|Marvel Super Heroes|223|R|{1}{G}{U}|Legendary Creature - Human Dinosaur Hero|2|2|Whenever you draw your second card each turn, until end of turn, Moon Girl and Devil Dinosaur's base power and toughness become 6/6 and they gain trample.$Whenever an artifact you control enters, draw a card. This ability triggers only once each turn.| +World War Hulk|Marvel Super Heroes|304|R|{3}{G}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- The next red or green creature spell you cast this turn can be cast without paying its mana cost.$II -- Put three +1/+1 counters on target creature you control.$III -- Choose target creature you control. Until end of turn, double its power and toughness and it gains trample.| +The Coming of Galactus|Marvel Super Heroes|307|M|{2}{B}{B}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)$I -- Destroy up to one target nonland permanent.$II, III -- Each opponent loses 2 life.$IV -- Create Galactus, a legendary 16/16 black Elder alien creature token with flying, trample, and "Whenever Galactus attacks, destroy target land."| +Captain America, Super-Soldier|Marvel Super Heroes|387|M|{1}{W}{W}|Legendary Creature - Human Soldier Hero|3|2|First strike$Captain America enters with a shield counter on him.$As long as Captain America has a shield counter on him, you and other Heroes you control have hexproof.| +Bruce Banner|Marvel Super Heroes|390|M|{U}|Legendary Creature - Human Scientist Hero|1|1|{X}{X}, {T}: Draw X cards. Activate only as a sorcery.${2}{R}{R}{G}{G}: Transform Bruce Banner. Activate only as a sorcery.| +The Incredible Hulk|Marvel Super Heroes|390|M|{2}{R}{R}{G}{G}|1/1 Creature|8|8|Reach, trample$Enrage -- Whenever The Incredible Hulk is dealt damage, put a +1/+1 counter on him. If he's attacking, untap him and there is an additional combat phase after this phase.| +Namor the Sub-Mariner|Marvel Super Heroes|391|M|{1}{U}{U}|Legendary Creature - Mutant Merfolk Villain|*|4|Flying$Namor's power is equal to the number of Merfolk you control.$Whenever you cast a noncreature spell with one or more blue mana symbols in its mana cost, create that many 1/1 blue Merfolk creature tokens.| +Doctor Doom|Marvel Super Heroes|394|M|{4}{B}{B}|Legendary Creature - Human Scientist Villain|3|3|When Doctor Doom enters, create two 3/3 colorless Robot Villain artifact creature tokens named Doombot.$As long as you control an artifact creature or a Plan, Doctor Doom has indestructible.$At the beginning of your end step, you draw a card and lose 1 life.| +Invisible Woman|Marvel Super Heroes Commander|1|M|{2}{W}|Legendary Creature - Human Hero|3|3|At the beginning of combat on your turn, if you've cast a noncreature spell this turn, create a 0/3 colorless Wall creature token with defender and reach.$Whenever you attack, you may pay {R}{G}{W}{U}. When you do, target creature gets +1/+0 until end of turn for each creature you control and can't be blocked this turn.| +Mister Fantastic|Marvel Super Heroes Commander|2|M|{2}{U}|Legendary Creature - Human Scientist Hero|2|4|Vigilance, reach$At the beginning of combat on your turn, if you've cast a noncreature spell this turn, draw a card.${R}{G}{W}{U}, {T}: Copy target triggered ability you control twice. You may choose new targets for the copies.| +Human Torch|Marvel Super Heroes Commander|3|M|{3}{R}|Legendary Creature - Human Hero|3|2|At the beginning of combat on your turn, if you've cast a noncreature spell this turn, Human Torch gains flying, double strike, and haste until end of turn.$Whenever Human Torch attacks, you may pay {R}{G}{W}{U}. If you do, until end of turn, whenever he deals combat damage to an opponent, he deals that much damage to each other opponent.| +The Thing|Marvel Super Heroes Commander|4|M|{5}{G}|Legendary Creature - Human Hero|5|5|Trample$At the beginning of combat on your turn, if you've cast a noncreature spell this turn, put four +1/+1 counters on The Thing.$Whenever The Thing attacks, you may pay {R}{G}{W}{U}. When you do, double the number of each kind of counter on any number of target permanents you control.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 161d46c343c..7f142477ea4 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -178,6 +178,8 @@ Masters 25|A25| Magic: The Gathering-Commander|CMD| Magic: The Gathering-Conspiracy|CNS| Media Inserts|MBP| +Marvel Super Heroes|MSH| +Marvel Super Heroes Commander|MSC| Marvel's Spider-Man|SPM| Marvel's Spider-Man Eternal|SPE| March of the Machine|MOM| @@ -257,6 +259,8 @@ Special Guests|SPG| Super Series|SUS| Tarkir: Dragonstorm|TDM| Tarkir: Dragonstorm Commander|TDC| +Teenage Mutant Ninja Turtles|TMT| +Teenage Mutant Ninja Turtles Eternal|TMC| Theros|THS| Theros Beyond Death|THB| The Brothers' War|BRO|