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 aa163daaa4a..c45fb575270 100644
--- a/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java
+++ b/Mage.Client/src/main/java/mage/client/components/BracketLegalityLabel.java
@@ -4,8 +4,12 @@ import mage.MageObject;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.client.util.GUISizeHelper;
+import org.apache.log4j.Logger;
import java.awt.*;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;
@@ -16,22 +20,73 @@ import java.util.stream.Stream;
*
* Support:
* - [x] game changers
- * - [ ] infinite combos
+ * - [x] infinite combos
* - [x] mass land destruction
* - [x] extra turns
* - [x] tutors
+ * Features:
+ * - [x] find possible bracket level of the deck
+ * - [x] find affected cards by checking group
+ * - [x] can auto-generate infinite combos list, see verify test downloadAndPrepareCommanderBracketsData
+ * - [ ] TODO: tests
+ * - [ ] TODO: table - players brackets level disclose settings
+ * - [ ] TODO: generate - convert card name to xmage format and assert on bad names (ascii only)
*
* @author JayDi85
*/
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 (unsupported)";
+ private static final String GROUP_INFINITE_COMBOS = "Infinite 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 final BracketLevel level;
+ private static final Map> MAX_GROUP_LIMITS = new LinkedHashMap<>();
+
+ static {
+ // 1
+ // No cards from the Game Changer list.
+ // No intentional two-card infinite combos.
+ // No mass land destruction.
+ // No extra turn cards.
+ // Tutors should be sparse.
+ // 2
+ // No cards from the Game Changer list.
+ // No intentional two-card infinite combos.
+ // No mass land destruction.
+ // Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
+ // Tutors should be sparse.
+ // 3
+ // Up to three (3) cards from the Game Changer list.
+ // No intentional early game two-card infinite combos.
+ // No mass land destruction.
+ // Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
+ // 4
+ // 5
+ // allow any cards
+
+ // cards limits per brackets level, it's ok to use 99 as max
+ // group - levels 0, 1, 2, 3, 4, 5
+ MAX_GROUP_LIMITS.put(GROUP_GAME_CHANGES,
+ Arrays.asList(0, 0, 0, 3, 99, 99));
+ MAX_GROUP_LIMITS.put(GROUP_INFINITE_COMBOS,
+ Arrays.asList(0, 0, 0, 0, 99, 99));
+ MAX_GROUP_LIMITS.put(GROUP_MASS_LAND_DESTRUCTION,
+ 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";
+
+ private final String fullName;
+ private final String shortName;
+ private final int maxLevel;
private final List foundGameChangers = new ArrayList<>();
private final List foundInfiniteCombos = new ArrayList<>();
@@ -41,28 +96,14 @@ public class BracketLegalityLabel extends LegalityLabel {
private final List badCards = new ArrayList<>();
private final List fullGameChanges = new ArrayList<>();
+ private final Set fullInfiniteCombos = new HashSet<>(); // card1@card2, sorted by names, name must be xmage compatible
- public enum BracketLevel {
- BRACKET_1("Bracket 1"),
- BRACKET_2_3("Bracket 2-3"),
- BRACKET_4_5("Bracket 4-5");
-
- private final String name;
-
- BracketLevel(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return this.name;
- }
- }
-
- public BracketLegalityLabel(BracketLevel level) {
- super(level.toString(), null);
- this.level = level;
- setPreferredSize(DIM_PREFERRED);
+ public BracketLegalityLabel(String fullName, String shortName, int maxLevel) {
+ super(shortName, null);
+ this.fullName = fullName;
+ this.shortName = shortName;
+ this.maxLevel = maxLevel;
+ setPreferredSize(DIM_PREFERRED_1_OF_5);
}
@Override
@@ -72,49 +113,26 @@ public class BracketLegalityLabel extends LegalityLabel {
private void validateBracketLevel() {
this.badCards.clear();
- switch (this.level) {
- case BRACKET_1:
- // No cards from the Game Changer list.
- // No intentional two-card infinite combos.
- // No mass land destruction.
- // No extra turn cards.
- // Tutors should be sparse.
- this.badCards.addAll(this.foundGameChangers);
- this.badCards.addAll(this.foundInfiniteCombos);
- this.badCards.addAll(this.foundMassLandDestruction);
- this.badCards.addAll(this.foundExtraTurn);
- if (this.foundTutors.size() > 3) {
- this.badCards.addAll(this.foundTutors);
- }
- break;
- case BRACKET_2_3:
- // 2
- // No cards from the Game Changer list.
- // No intentional two-card infinite combos.
- // No mass land destruction.
- // Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
- // Tutors should be sparse.
- // 3
- // Up to three (3) cards from the Game Changer list.
- // No intentional early game two-card infinite combos.
- // No mass land destruction.
- // Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
- if (this.foundGameChangers.size() > 3) {
- this.badCards.addAll(this.foundGameChangers);
- }
- this.badCards.addAll(this.foundInfiniteCombos);
- this.badCards.addAll(this.foundMassLandDestruction);
- if (this.foundExtraTurn.size() > 3) {
- this.badCards.addAll(this.foundExtraTurn);
- }
- // this.badCards.addAll(this.foundTutors); // allow any amount
- break;
- case BRACKET_4_5:
- // allow any cards
- break;
- default:
- throw new IllegalArgumentException("Unsupported level: " + this.level);
+
+ if (this.foundGameChangers.size() > getMaxCardsLimit(GROUP_GAME_CHANGES)) {
+ this.badCards.addAll(this.foundGameChangers);
}
+ if (this.foundInfiniteCombos.size() > getMaxCardsLimit(GROUP_INFINITE_COMBOS)) {
+ this.badCards.addAll(this.foundInfiniteCombos);
+ }
+ if (this.foundMassLandDestruction.size() > getMaxCardsLimit(GROUP_MASS_LAND_DESTRUCTION)) {
+ this.badCards.addAll(this.foundMassLandDestruction);
+ }
+ 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) {
+ return MAX_GROUP_LIMITS.get(groupName).get(this.maxLevel);
}
@Override
@@ -122,31 +140,41 @@ public class BracketLegalityLabel extends LegalityLabel {
collectAll(deck);
validateBracketLevel();
- int infoFontSize = Math.round(GUISizeHelper.cardTooltipFont.getSize() * 0.6f);
+ int infoFontHeaderSize = Math.round(GUISizeHelper.cardTooltipFont.getSize() * 1.0f);
+ int infoFontTextSize = Math.round(GUISizeHelper.cardTooltipFont.getSize() * 0.6f);
// show all found cards in any use cases
Color showColor = this.badCards.isEmpty() ? COLOR_LEGAL : COLOR_NOT_LEGAL;
List showInfo = new ArrayList<>();
if (this.badCards.isEmpty()) {
- showInfo.add("Deck is GOOD for " + this.level + "
");
+ showInfo.add(String.format("Deck is GOOD for %s
",
+ infoFontHeaderSize,
+ this.fullName
+ ));
} else {
- showInfo.add("Deck is BAD for " + this.level + "
");
+ showInfo.add(String.format("Deck is BAD for %s
",
+ infoFontHeaderSize,
+ this.fullName
+ ));
showInfo.add("(click here to select all bad cards)
");
}
Map> groups = new LinkedHashMap<>();
- groups.put(GROUP_GAME_CHANGES, this.foundGameChangers);
- groups.put(GROUP_INFINITE_COMBOS, this.foundInfiniteCombos);
- groups.put(GROUP_MASS_LAND_DESTRUCTION, this.foundMassLandDestruction);
- groups.put(GROUP_EXTRA_TURN, this.foundExtraTurn);
- groups.put(GROUP_TUTORS, this.foundTutors);
+ groups.put(GROUP_GAME_CHANGES + getStats(GROUP_GAME_CHANGES), this.foundGameChangers);
+ 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("
");
- showInfo.add("" + group + ": " + cards.size() + "");
- if (!cards.isEmpty()) {
- showInfo.add("");
+ showInfo.add("" + group + "");
+ if (cards.isEmpty()) {
+ showInfo.add("");
+ showInfo.add("- no cards
");
+ showInfo.add("
");
+ } else {
+ showInfo.add("");
cards.forEach(s -> showInfo.add(String.format("- %s
", s)));
showInfo.add("
");
}
@@ -156,6 +184,39 @@ public class BracketLegalityLabel extends LegalityLabel {
showState(showColor, showText, false);
}
+ private String getStats(String groupName) {
+ int currentAmount = 0;
+ switch (groupName) {
+ case GROUP_GAME_CHANGES:
+ currentAmount = this.foundGameChangers.size();
+ break;
+ case GROUP_INFINITE_COMBOS:
+ currentAmount = this.foundInfiniteCombos.size();
+ break;
+ case GROUP_MASS_LAND_DESTRUCTION:
+ currentAmount = this.foundMassLandDestruction.size();
+ break;
+ case GROUP_EXTRA_TURN:
+ currentAmount = this.foundExtraTurn.size();
+ break;
+ case GROUP_TUTORS:
+ currentAmount = this.foundTutors.size();
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown group " + groupName);
+ }
+ int maxAmount = MAX_GROUP_LIMITS.get(groupName).get(this.maxLevel);
+
+ String info;
+ if (currentAmount > maxAmount) {
+ info = " (%s of %s)";
+ } else {
+ info = " (%s of %s)";
+ }
+
+ return String.format(info, currentAmount, maxAmount == 99 ? "any" : maxAmount);
+ }
+
private void collectAll(Deck deck) {
collectGameChangers(deck);
collectInfiniteCombos(deck);
@@ -243,8 +304,64 @@ public class BracketLegalityLabel extends LegalityLabel {
}
private void collectInfiniteCombos(Deck deck) {
- // TODO: implement
this.foundInfiniteCombos.clear();
+
+ if (this.fullInfiniteCombos.isEmpty()) {
+ InputStream in = BracketLegalityLabel.class.getClassLoader().getResourceAsStream(RESOURCE_INFINITE_COMBOS);
+ if (in == null) {
+ throw new RuntimeException("Commander brackets: can't load infinite combos list");
+ }
+ try (InputStreamReader input = new InputStreamReader(in);
+ BufferedReader reader = new BufferedReader(input)) {
+ String line = reader.readLine();
+ while (line != null) {
+ try {
+ line = line.trim();
+ if (line.startsWith("#")) {
+ continue;
+ }
+ List cards = Arrays.asList(line.split("@"));
+ if (cards.size() != 2) {
+ logger.warn("wrong line format in commander brackets file: " + line);
+ continue;
+ }
+
+ Collections.sort(cards);
+ this.fullInfiniteCombos.add(String.join("@", cards));
+ } finally {
+ line = reader.readLine();
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Tokens brackets: can't load infinite combos list - " + e);
+ }
+ }
+
+ // search and check all x2 combinations
+ List deckCards = new ArrayList<>();
+ Set foundCards = new HashSet<>();
+ deckCards.addAll(deck.getCards());
+ deckCards.addAll(deck.getSideboard());
+ for (Card card1 : deckCards) {
+ for (Card card2 : deckCards) {
+ if (card1 == card2) {
+ continue;
+ }
+ List names = Arrays.asList(card1.getName(), card2.getName());
+ Collections.sort(names);
+ String deckCombo = String.join("@", names);
+ if (this.fullInfiniteCombos.contains(deckCombo)) {
+ foundCards.add(card1);
+ foundCards.add(card2);
+ break;
+ }
+ }
+ }
+
+ foundCards.stream()
+ .map(MageObject::getName)
+ .sorted()
+ .forEach(this.foundInfiniteCombos::add);
}
private void collectMassLandDestruction(Deck deck) {
diff --git a/Mage.Client/src/main/java/mage/client/components/EdhPowerLevelLegalityLabel.java b/Mage.Client/src/main/java/mage/client/components/EdhPowerLevelLegalityLabel.java
index fd96815df30..0dac9d88697 100644
--- a/Mage.Client/src/main/java/mage/client/components/EdhPowerLevelLegalityLabel.java
+++ b/Mage.Client/src/main/java/mage/client/components/EdhPowerLevelLegalityLabel.java
@@ -2,7 +2,6 @@ package mage.client.components;
import mage.cards.decks.Deck;
import mage.client.util.GUISizeHelper;
-import mage.client.util.gui.GuiDisplayUtil;
import mage.deck.Commander;
import java.util.ArrayList;
@@ -22,7 +21,7 @@ public class EdhPowerLevelLegalityLabel extends LegalityLabel {
public EdhPowerLevelLegalityLabel() {
super("EDH Power Level: ?", null);
- setPreferredSize(DIM_PREFERRED_X3);
+ setPreferredSize(DIM_PREFERRED_3_OF_3);
}
@Override
diff --git a/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java b/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java
index 95d2a13c7bf..6f02be7bebe 100644
--- a/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java
+++ b/Mage.Client/src/main/java/mage/client/components/LegalityLabel.java
@@ -25,9 +25,10 @@ public class LegalityLabel extends JLabel {
protected static final Color COLOR_TEXT = new Color(255, 255, 255);
protected static final Dimension DIM_MINIMUM = new Dimension(75, 25);
protected static final Dimension DIM_MAXIMUM = new Dimension(150, 75);
- protected static final Dimension DIM_PREFERRED = new Dimension(75, 25);
- protected static final Dimension DIM_PREFERRED_X2 = new Dimension(DIM_PREFERRED.width * 2 + 5, 25);
- protected static final Dimension DIM_PREFERRED_X3 = new Dimension(DIM_PREFERRED.width * 3 + 5 + 5, 25);
+ protected static final Dimension DIM_PREFERRED_1_OF_3 = new Dimension(75, 25);
+ protected static final Dimension DIM_PREFERRED_2_OF_3 = new Dimension(DIM_PREFERRED_1_OF_3.width * 2 + 5, 25);
+ protected static final Dimension DIM_PREFERRED_3_OF_3 = new Dimension(DIM_PREFERRED_1_OF_3.width * 3 + 5 * 2, 25);
+ protected static final Dimension DIM_PREFERRED_1_OF_5 = new Dimension((DIM_PREFERRED_3_OF_3.width - 5 * 4) / 5, 25);
protected static final int TOOLTIP_TABLE_WIDTH = 400; // size of the label's tooltip
protected static final int TOOLTIP_MAX_ERRORS = 20; // max errors to show in tooltip
@@ -54,7 +55,7 @@ public class LegalityLabel extends JLabel {
setMaximumSize(DIM_MAXIMUM);
setName(text); // NOI18N
setOpaque(true);
- setPreferredSize(DIM_PREFERRED);
+ setPreferredSize(DIM_PREFERRED_1_OF_3);
}
/**
@@ -80,7 +81,7 @@ public class LegalityLabel extends JLabel {
setMinimumSize(DIM_MINIMUM);
setMaximumSize(DIM_MAXIMUM);
setOpaque(true);
- setPreferredSize(DIM_PREFERRED);
+ setPreferredSize(DIM_PREFERRED_1_OF_3);
}
/**
@@ -91,7 +92,7 @@ public class LegalityLabel extends JLabel {
button.setHorizontalAlignment(SwingConstants.CENTER);
button.setMinimumSize(DIM_MINIMUM);
button.setMaximumSize(DIM_MAXIMUM);
- button.setPreferredSize(DIM_PREFERRED);
+ button.setPreferredSize(DIM_PREFERRED_1_OF_3);
return button;
}
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckLegalityPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckLegalityPanel.java
index 29f7fce598f..f9ecdb01acd 100644
--- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckLegalityPanel.java
+++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckLegalityPanel.java
@@ -107,9 +107,11 @@ public class DeckLegalityPanel extends javax.swing.JPanel {
// extra buttons like score
this.add(new EdhPowerLevelLegalityLabel());
// only 3 buttons allowed for one line
- this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_1));
- this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_2_3));
- this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_4_5));
+ this.add(new BracketLegalityLabel("Bracket 1", "B1", 1));
+ this.add(new BracketLegalityLabel("Bracket 2", "B2", 2));
+ this.add(new BracketLegalityLabel("Bracket 3", "B3", 3));
+ this.add(new BracketLegalityLabel("Bracket 4", "B4", 4));
+ this.add(new BracketLegalityLabel("Bracket 5", "B5", 5));
addHidePanelButton();
diff --git a/Mage.Client/src/main/java/mage/client/remote/XmageURLConnection.java b/Mage.Client/src/main/java/mage/client/remote/XmageURLConnection.java
index 4ff6869ee0e..ef4e38fba03 100644
--- a/Mage.Client/src/main/java/mage/client/remote/XmageURLConnection.java
+++ b/Mage.Client/src/main/java/mage/client/remote/XmageURLConnection.java
@@ -291,16 +291,25 @@ public class XmageURLConnection {
}
}
+ public static String downloadText(String resourceUrl) {
+ return downloadText(resourceUrl, null);
+ }
+
/**
* Fast download of text data
*
+ * @param additionalHeaders set extra headers like application/json
+ *
* @return downloaded text on OK 200 response or empty on any other errors
*/
- public static String downloadText(String resourceUrl) {
+ public static String downloadText(String resourceUrl, Map additionalHeaders) {
XmageURLConnection con = new XmageURLConnection(resourceUrl);
con.startConnection();
if (con.isConnected()) {
try {
+ if (additionalHeaders != null) {
+ con.setRequestHeaders(additionalHeaders);
+ }
con.connect();
if (con.getResponseCode() == 200) {
return con.getGoodResponseAsString();
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 a6479a6c40a..19aecedcf0e 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
@@ -2201,6 +2201,7 @@ public class ScryfallImageSupportTokens {
put("WHO/Human/2", "https://api.scryfall.com/cards/twho/5/en?format=image");
put("WHO/Human Noble", "https://api.scryfall.com/cards/twho/7/en?format=image");
put("WHO/Mark of the Rani", "https://api.scryfall.com/cards/twho/15?format=image");
+ put("WHO/Mutant", "https://api.scryfall.com/cards/twho/18?format=image");
put("WHO/Soldier", "https://api.scryfall.com/cards/twho/8?format=image");
put("WHO/Treasure/1", "https://api.scryfall.com/cards/twho/28?format=image");
put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?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 650eedf5e98..a8fb8ddc6c1 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
@@ -853,7 +853,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
connection.startConnection();
if (connection.isConnected()) {
- // custom headers (ues
+ // custom headers
connection.setRequestHeaders(selectedSource.getHttpRequestHeaders(currentUrl));
try {
diff --git a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java
index b95937a88b9..6a7847ec4fc 100644
--- a/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java
+++ b/Mage.Common/src/main/java/mage/utils/testers/ChooseAmountTestableDialog.java
@@ -15,6 +15,8 @@ import java.util.List;
/**
* Part of testable game dialogs
*
+ * It's a complex dialog with 2 steps: choose targets list + distribute amount between targets
+ *
* Supported methods:
* - player.chooseTarget(amount)
*
diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java
index 22a4659dd78..0a66bac8f9d 100644
--- a/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java
+++ b/Mage.Common/src/main/java/mage/utils/testers/GetAmountTestableDialog.java
@@ -11,6 +11,8 @@ import java.util.List;
/**
* Part of testable game dialogs
*
+ * Its simple dialog to get some amount (example: part of chooseTargetAmount)
+ *
* Supported methods:
* - player.getAmount()
*
diff --git a/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java
new file mode 100644
index 00000000000..2c1f9046f3a
--- /dev/null
+++ b/Mage.Common/src/main/java/mage/utils/testers/GetMultiAmountTestableDialog.java
@@ -0,0 +1,118 @@
+package mage.utils.testers;
+
+import mage.abilities.Ability;
+import mage.constants.MultiAmountType;
+import mage.constants.Outcome;
+import mage.game.Game;
+import mage.players.Player;
+import mage.util.MultiAmountMessage;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Part of testable game dialogs
+ *
+ * Its simple dialog to get distributed value between multiple options (example: part of combat damage distributing)
+ *
+ * Supported methods:
+ * - player.getMultiAmountWithIndividualConstraints()
+ * - player.getMultiAmount() - simple version of constraints
+ *
+ * @author JayDi85
+ */
+class GetMultiAmountTestableDialog extends BaseTestableDialog {
+
+ boolean isYou; // who choose - you or opponent
+ int totalMin;
+ int totalMax;
+ List amountOptions = new ArrayList<>();
+
+ /**
+ * @param options min, max, default
+ */
+ public GetMultiAmountTestableDialog(boolean isYou, String info, int totalMin, int totalMax, List> options) {
+ super(String.format("player.getMultiAmount(%s)", isYou ? "you" : "AI"),
+ String.format("%s, %d options from [%d-%d]", info, options.size(), totalMin, totalMax),
+ "");
+ this.isYou = isYou;
+ this.totalMin = totalMin;
+ this.totalMax = totalMax;
+ int optionNumber = 0;
+ for (List single : options) {
+ optionNumber++;
+ String mes = "option " + optionNumber + " with html";
+ this.amountOptions.add(new MultiAmountMessage(mes, single.get(0), single.get(1), single.get(2)));
+ }
+ }
+
+ @Override
+ public List showDialog(Player player, Ability source, Game game, Player opponent) {
+ Player choosingPlayer = this.isYou ? player : opponent;
+ //String message = "message with html";
+ List chooseRes;
+ List options = this.amountOptions.stream().map(MultiAmountMessage::copy).collect(Collectors.toList());
+ chooseRes = choosingPlayer.getMultiAmountWithIndividualConstraints(
+ Outcome.Benefit,
+ options,
+ this.totalMin,
+ this.totalMax,
+ MultiAmountType.DAMAGE,
+ game
+ );
+
+ List result = new ArrayList<>();
+ result.add(getGroup() + " - " + this.getName());
+ int selectedIndex = -1;
+ int selectedTotal = 0;
+ for (Integer selectedValue : chooseRes) {
+ selectedIndex++;
+ selectedTotal += selectedValue;
+ MultiAmountMessage option = this.amountOptions.get(selectedIndex);
+ result.add(String.format("%d from [%d-%d, def %d]",
+ selectedValue,
+ option.min,
+ option.max,
+ option.defaultValue
+ ));
+ }
+ result.add("total selected: " + selectedTotal);
+
+ return result;
+ }
+
+ static public void register(TestableDialogsRunner runner) {
+ List isYous = Arrays.asList(false, true);
+ for (boolean isYou : isYous) {
+ // make sure default values are valid due min/max settings
+
+ // single target
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 1, genSameOptions(1, 0, 1, 0)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 0 def", 0, 3, genSameOptions(1, 0, 3, 0)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 1, genSameOptions(1, 1, 1, 1)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 1 def", 1, 3, genSameOptions(1, 1, 3, 1)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 5 def", 0, 10, genSameOptions(1, 0, 10, 5)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "one, 10 def", 10, 10, genSameOptions(1, 0, 10, 10)));
+ // multiple targets
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 0 def", 0, 5, genSameOptions(3, 0, 3, 0)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 0 def", 0, 5, genSameOptions(3, 0, 3, 0)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 1 def", 1, 5, genSameOptions(3, 1, 3, 1)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 1 def", 1, 5, genSameOptions(3, 1, 3, 1)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 0, 60, genSameOptions(3, 0, 60, 20)));
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "many, 20 def", 60, 60, genSameOptions(3, 0, 60, 20)));
+ // big lists
+ runner.registerDialog(new GetMultiAmountTestableDialog(isYou, "big list", 0, 100, genSameOptions(20, 0, 100, 0)));
+ }
+ }
+
+ private static List> genSameOptions(int amount, int min, int max, int def) {
+ List> res = new ArrayList<>();
+ for (int i = 0; i < amount; i++) {
+ // min, max, default
+ res.add(Arrays.asList(min, max, def));
+ }
+ return res;
+ }
+}
diff --git a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java
index 6217877dbce..3c2cfb3840d 100644
--- a/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java
+++ b/Mage.Common/src/main/java/mage/utils/testers/TestableDialogsRunner.java
@@ -31,7 +31,7 @@ import java.util.stream.Collectors;
* [x] choosePile
* [x] announceX
* [x] getAmount
- * [ ] getMultiAmountWithIndividualConstraints // TODO: implement
+ * [x] getMultiAmountWithIndividualConstraints
*
* Support of priority dialogs (can be called by game engine, some can be implemented in theory):
* --- priority
@@ -75,6 +75,7 @@ public class TestableDialogsRunner {
ChooseAmountTestableDialog.register(this);
AnnounceXTestableDialog.register(this);
GetAmountTestableDialog.register(this);
+ GetMultiAmountTestableDialog.register(this);
}
void registerDialog(TestableDialog dialog) {
diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml
index bef5a819349..1e7a126def9 100644
--- a/Mage.Server/release/config/config.xml
+++ b/Mage.Server/release/config/config.xml
@@ -96,8 +96,8 @@
-
-
+
+
@@ -108,62 +108,62 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java
index b603e88069b..51f43b87591 100644
--- a/Mage.Server/src/main/java/mage/server/Main.java
+++ b/Mage.Server/src/main/java/mage/server/Main.java
@@ -4,7 +4,9 @@ import mage.cards.ExpansionSet;
import mage.cards.RateCard;
import mage.cards.Sets;
import mage.cards.decks.DeckValidatorFactory;
-import mage.cards.repository.*;
+import mage.cards.repository.CardScanner;
+import mage.cards.repository.PluginClassloaderRegistery;
+import mage.cards.repository.RepositoryUtil;
import mage.game.match.MatchType;
import mage.game.tournament.TournamentType;
import mage.interfaces.MageServer;
@@ -507,8 +509,19 @@ public final class Main {
private static Class> loadPlugin(Plugin plugin) {
try {
- classLoader.addURL(new File(pluginFolder, plugin.getJar()).toURI().toURL());
logger.debug("Loading plugin: " + plugin.getClassName());
+ if (plugin.getName() == null || plugin.getName().isEmpty()
+ || plugin.getJar() == null || plugin.getJar().isEmpty()
+ || plugin.getClassName() == null || plugin.getClassName().isEmpty()
+ ) {
+ logger.error(String.format("Can't load plugin, found miss fields in config.xml: %s, %s, %s",
+ plugin.getName(),
+ plugin.getJar(),
+ plugin.getClassName()
+ ));
+ return null;
+ }
+ classLoader.addURL(new File(pluginFolder, plugin.getJar()).toURI().toURL());
return Class.forName(plugin.getClassName(), true, classLoader);
} catch (ClassNotFoundException ex) {
logger.warn(new StringBuilder("Plugin not Found: ").append(plugin.getClassName()).append(" - ").append(plugin.getJar()).append(" - check plugin folder"), ex);
diff --git a/Mage.Server/src/main/java/mage/server/game/GameFactory.java b/Mage.Server/src/main/java/mage/server/game/GameFactory.java
index a0a3621e0c0..1adcec33aba 100644
--- a/Mage.Server/src/main/java/mage/server/game/GameFactory.java
+++ b/Mage.Server/src/main/java/mage/server/game/GameFactory.java
@@ -51,7 +51,7 @@ public enum GameFactory {
}
public void addGameType(String name, MatchType matchType, Class game) {
- if (game != null) {
+ if (matchType != null && game != null) {
this.games.put(name, game);
this.gameTypes.put(name, matchType);
this.gameTypeViews.add(new GameTypeView(matchType));
diff --git a/Mage.Server/src/main/java/mage/server/game/PlayerFactory.java b/Mage.Server/src/main/java/mage/server/game/PlayerFactory.java
index a8150268f06..2f9e46d91c3 100644
--- a/Mage.Server/src/main/java/mage/server/game/PlayerFactory.java
+++ b/Mage.Server/src/main/java/mage/server/game/PlayerFactory.java
@@ -45,12 +45,10 @@ public enum PlayerFactory {
}
public void addPlayerType(String name, Class playerType) {
+ // will raise error and stop on unknown player and that's ok - it's require HumanPlayer anyway
PlayerType type = PlayerType.getByDescription(name);
- if (type != null) {
- if (playerType != null) {
- this.playerTypes.put(type, playerType);
- }
+ if (playerType != null) {
+ this.playerTypes.put(type, playerType);
}
}
-
}
diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentFactory.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentFactory.java
index fee2de4c3fe..71e7c0a219d 100644
--- a/Mage.Server/src/main/java/mage/server/tournament/TournamentFactory.java
+++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentFactory.java
@@ -93,7 +93,7 @@ public enum TournamentFactory {
public void addTournamentType(String name, TournamentType tournamentType, Class tournament) {
- if (tournament != null) {
+ if (tournamentType != null && tournament != null) {
this.tournaments.put(name, tournament);
this.tournamentTypes.put(name, tournamentType);
this.tournamentTypeViews.add(new TournamentTypeView(tournamentType));
diff --git a/Mage.Sets/src/mage/cards/a/Aberrant.java b/Mage.Sets/src/mage/cards/a/Aberrant.java
index ea06d8710c0..dc2f62010a8 100644
--- a/Mage.Sets/src/mage/cards/a/Aberrant.java
+++ b/Mage.Sets/src/mage/cards/a/Aberrant.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -42,7 +42,7 @@ public final class Aberrant extends CardImpl {
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.withFlavorWord("Heavy Power Hammer");
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/AbstergoEntertainment.java b/Mage.Sets/src/mage/cards/a/AbstergoEntertainment.java
index 6027d609d90..f405a13545b 100644
--- a/Mage.Sets/src/mage/cards/a/AbstergoEntertainment.java
+++ b/Mage.Sets/src/mage/cards/a/AbstergoEntertainment.java
@@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
@@ -24,7 +24,10 @@ import java.util.UUID;
*/
public final class AbstergoEntertainment extends CardImpl {
- private static final FilterCard filter = new FilterHistoricCard("historic card from your graveyard");
+ private static final FilterCard filter = new FilterCard("historic card from your graveyard");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
public AbstergoEntertainment(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
diff --git a/Mage.Sets/src/mage/cards/a/AbzanBeastmaster.java b/Mage.Sets/src/mage/cards/a/AbzanBeastmaster.java
index 07baf140a0e..a413743d361 100644
--- a/Mage.Sets/src/mage/cards/a/AbzanBeastmaster.java
+++ b/Mage.Sets/src/mage/cards/a/AbzanBeastmaster.java
@@ -1,36 +1,35 @@
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.common.ControlsCreatureGreatestToughnessCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
+import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
+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 LevelX2
*/
public final class AbzanBeastmaster extends CardImpl {
public AbzanBeastmaster(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.DOG);
this.subtype.add(SubType.SHAMAN);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
// At the beginning of your upkeep, draw a card if you control the creature with the greatest toughness or tied for the greatest toughness.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1)),
- ControlsCreatureGreatestToughnessCondition.instance,
- "At the beginning of your upkeep, draw a card if you control the creature with the greatest toughness or tied for the greatest toughness."
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect(
+ new DrawCardSourceControllerEffect(1), ControlsCreatureGreatestToughnessCondition.instance,
+ "draw a card if you control the creature with the greatest toughness or tied for the greatest toughness"
+ )));
}
private AbzanBeastmaster(final AbzanBeastmaster card) {
diff --git a/Mage.Sets/src/mage/cards/a/AcclaimedContender.java b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java
index 0450d449e5f..2fbf272c272 100644
--- a/Mage.Sets/src/mage/cards/a/AcclaimedContender.java
+++ b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@@ -25,7 +24,7 @@ import java.util.UUID;
*/
public final class AcclaimedContender extends CardImpl {
- private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT);
+ private static final FilterPermanent filter = new FilterControlledPermanent(SubType.KNIGHT, "you control another Knight");
private static final FilterCard filter2
= new FilterCard("a Knight, Aura, Equipment, or legendary artifact card");
@@ -53,14 +52,9 @@ public final class AcclaimedContender extends CardImpl {
this.toughness = new MageInt(3);
// When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
- 5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM
- )), condition, "When {this} enters, " +
- "if you control another Knight, look at the top five cards of your library. " +
- "You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them " +
- "and put it into your hand. Put the rest on the bottom of your library in a random order."
- ));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
+ 5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM
+ )).withInterveningIf(condition));
}
private AcclaimedContender(final AcclaimedContender card) {
diff --git a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java
index 11eda4d0318..d429f82da8c 100644
--- a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java
+++ b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java
@@ -6,7 +6,6 @@ import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CompletedDungeonCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect;
@@ -22,8 +21,6 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.ZombieToken;
import mage.players.Player;
-import mage.target.TargetPermanent;
-import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetSacrifice;
import mage.watchers.common.CompletedDungeonWatcher;
@@ -44,13 +41,9 @@ public final class AcererakTheArchlich extends CardImpl {
this.toughness = new MageInt(5);
// When Acererak the Archlich enters the battlefield, if you have not completed Tomb of Annihilation, return Acererak the Archlich to its owner's hand and venture into the dungeon.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new ReturnToHandSourceEffect(true)),
- AcererakTheArchlichCondition.instance, "When {this} enters, " +
- "if you haven't completed Tomb of Annihilation, return {this} " +
- "to its owner's hand and venture into the dungeon."
- );
- ability.addEffect(new VentureIntoTheDungeonEffect());
+ Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandSourceEffect(true))
+ .withInterveningIf(AcererakTheArchlichCondition.instance);
+ ability.addEffect(new VentureIntoTheDungeonEffect().concatBy("and"));
ability.addHint(CurrentDungeonHint.instance);
ability.addHint(CompletedDungeonCondition.getHint());
this.addAbility(ability, new CompletedDungeonWatcher());
@@ -78,6 +71,11 @@ enum AcererakTheArchlichCondition implements Condition {
source.getControllerId(), game
).contains("Tomb of Annihilation");
}
+
+ @Override
+ public String toString() {
+ return "you haven't completed Tomb of Annihilation";
+ }
}
class AcererakTheArchlichEffect extends OneShotEffect {
diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java b/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java
index 332776d8e14..36f48cb6f75 100644
--- a/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java
+++ b/Mage.Sets/src/mage/cards/a/AdaptiveTrainingPost.java
@@ -11,6 +11,7 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
@@ -21,7 +22,7 @@ import java.util.UUID;
*/
public final class AdaptiveTrainingPost extends CardImpl {
- private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, 0, 2);
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, ComparisonType.FEWER_THAN, 3);
public AdaptiveTrainingPost(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}");
diff --git a/Mage.Sets/src/mage/cards/a/AdherentOfHope.java b/Mage.Sets/src/mage/cards/a/AdherentOfHope.java
index df3e76f6db4..62f145afd02 100644
--- a/Mage.Sets/src/mage/cards/a/AdherentOfHope.java
+++ b/Mage.Sets/src/mage/cards/a/AdherentOfHope.java
@@ -1,45 +1,41 @@
package mage.cards.a;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.hint.ConditionHint;
+import mage.abilities.hint.Hint;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
-import mage.filter.common.FilterControlledPermanent;
+import mage.filter.common.FilterControlledPlaneswalkerPermanent;
import java.util.UUID;
/**
- *
* @author htrajan
*/
public final class AdherentOfHope extends CardImpl {
- private static final FilterControlledPermanent filter = new FilterControlledPermanent();
-
- static {
- filter.add(CardType.PLANESWALKER.getPredicate());
- filter.add(SubType.BASRI.getPredicate());
- }
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
+ new FilterControlledPlaneswalkerPermanent(SubType.BASRI, "you control a Basri planeswalker")
+ );
+ private static final Hint hint = new ConditionHint(condition);
public AdherentOfHope(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(1);
// At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on Adherent of Hope.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())),
- new PermanentsOnTheBattlefieldCondition(filter),
- "At the beginning of combat on your turn, if you control a Basri planeswalker, put a +1/+1 counter on {this}."));
+ this.addAbility(new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())).withInterveningIf(condition).addHint(hint));
}
private AdherentOfHope(final AdherentOfHope card) {
diff --git a/Mage.Sets/src/mage/cards/a/Adrestia.java b/Mage.Sets/src/mage/cards/a/Adrestia.java
index c0df6888563..7536ee8ad98 100644
--- a/Mage.Sets/src/mage/cards/a/Adrestia.java
+++ b/Mage.Sets/src/mage/cards/a/Adrestia.java
@@ -1,40 +1,38 @@
package mage.cards.a;
-import java.util.*;
-
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
-import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.AddCardSubTypeSourceEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
-import mage.constants.*;
-import mage.abilities.keyword.IslandwalkAbility;
import mage.abilities.keyword.CrewAbility;
+import mage.abilities.keyword.IslandwalkAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
+import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.watchers.Watcher;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
/**
- *
* @author Grath
*/
public final class Adrestia extends CardImpl {
- private static final Condition condition = AdrestiaCondition.instance;
public Adrestia(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
-
+
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(4);
@@ -44,16 +42,14 @@ public final class Adrestia extends CardImpl {
this.addAbility(new IslandwalkAbility());
// Whenever Adrestia attacks, if an Assassin crewed it this turn, draw a card. Adrestia becomes an Assassin in addition to its other types until end of turn.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false),
- condition, "Whenever {this} attacks, if an Assassin crewed it this turn, draw a card. {this} becomes an Assassin in addition to its other types until end of turn.");
+ Ability ability = new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false)
+ .withInterveningIf(AdrestiaCondition.instance);
ability.addEffect(new AddCardSubTypeSourceEffect(Duration.EndOfTurn, true, SubType.ASSASSIN));
ability.addHint(AdrestiaCondition.getHint());
this.addAbility(ability, new AdrestiaWatcher());
// Crew 1
this.addAbility(new CrewAbility(1));
-
}
private Adrestia(final Adrestia card) {
@@ -68,13 +64,18 @@ public final class Adrestia extends CardImpl {
enum AdrestiaCondition implements Condition {
instance;
- private static final Hint hint = new ConditionHint(instance, "an Assassin crewed it this turn");
+ private static final Hint hint = new ConditionHint(instance);
@Override
public boolean apply(Game game, Ability source) {
return AdrestiaWatcher.checkIfAssassinCrewed(source.getSourcePermanentOrLKI(game), game);
}
+ @Override
+ public String toString() {
+ return "an Assassin crewed it this turn";
+ }
+
public static Hint getHint() {
return hint;
}
@@ -97,8 +98,7 @@ class AdrestiaWatcher extends Watcher {
if (crewer != null) {
if (!crewMap.containsKey(vehicle)) {
crewMap.put(vehicle, filter.match(crewer, game));
- }
- else {
+ } else {
crewMap.put(vehicle, crewMap.get(vehicle) || filter.match(crewer, game));
}
}
diff --git a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java
index fae375b3700..0aaed9d279b 100644
--- a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java
+++ b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.common.LandsYouControlHint;
@@ -46,13 +45,10 @@ public final class AerialSurveyor extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(
- new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)
- ), AerialSurveyorCondition.instance, "Whenever {this} attacks, if defending player " +
- "controls more lands than you, search your library for a basic Plains card, " +
- "put it onto the battlefield tapped, then shuffle."
- ).addHint(LandsYouControlHint.instance).addHint(AerialSurveyorHint.instance));
+ this.addAbility(new AttacksTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true))
+ .withInterveningIf(AerialSurveyorCondition.instance)
+ .addHint(LandsYouControlHint.instance)
+ .addHint(AerialSurveyorHint.instance));
// Crew 2
this.addAbility(new CrewAbility(2));
@@ -85,6 +81,11 @@ enum AerialSurveyorCondition implements Condition {
source.getControllerId(), source, game
);
}
+
+ @Override
+ public String toString() {
+ return "";
+ }
}
enum AerialSurveyorHint implements Hint {
diff --git a/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java b/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java
index d21de17365e..f4f9316a48e 100644
--- a/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java
+++ b/Mage.Sets/src/mage/cards/a/AetherfluxConduit.java
@@ -1,8 +1,5 @@
package mage.cards.a;
-import java.util.Optional;
-import java.util.UUID;
-
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
@@ -10,14 +7,20 @@ import mage.abilities.costs.common.PayEnergyCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
-import mage.abilities.effects.common.continuous.CastFromHandWithoutPayingManaCostEffect;
import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
+import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
+import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.stack.Spell;
+import mage.players.Player;
+import mage.util.CardUtil;
+
+import java.util.Optional;
+import java.util.UUID;
/**
* @author sobiech
@@ -28,14 +31,12 @@ public final class AetherfluxConduit extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}");
// Whenever you cast a spell, you get an amount of {E} equal to the amount of mana spent to cast that spell.
- this.addAbility(new SpellCastControllerTriggeredAbility(
- new AetherfluxConduitEffect(),false
- ));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AetherfluxConduitManaEffect(), false));
// {T}, Pay fifty {E}: Draw seven cards. You may cast any number of spells from your hand without paying their mana costs.
final Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(7), new TapSourceCost());
ability.addCost(new PayEnergyCost(50).setText("Pay fifty {E}"));
- ability.addEffect(new CastFromHandWithoutPayingManaCostEffect());
+ ability.addEffect(new AetherfluxConduitCastEffect());
this.addAbility(ability);
}
@@ -48,19 +49,21 @@ public final class AetherfluxConduit extends CardImpl {
return new AetherfluxConduit(this);
}
}
-class AetherfluxConduitEffect extends OneShotEffect {
- AetherfluxConduitEffect() {
+class AetherfluxConduitManaEffect extends OneShotEffect {
+
+ AetherfluxConduitManaEffect() {
super(Outcome.Benefit);
this.staticText = "you get an amount of {E} (energy counters) equal to the amount of mana spent to cast that spell";
}
- private AetherfluxConduitEffect(AetherfluxConduitEffect effect) {
+
+ private AetherfluxConduitManaEffect(AetherfluxConduitManaEffect effect) {
super(effect);
}
@Override
- public AetherfluxConduitEffect copy() {
- return new AetherfluxConduitEffect(this);
+ public AetherfluxConduitManaEffect copy() {
+ return new AetherfluxConduitManaEffect(this);
}
@Override
@@ -72,3 +75,31 @@ class AetherfluxConduitEffect extends OneShotEffect {
}
}
+class AetherfluxConduitCastEffect extends OneShotEffect {
+
+ AetherfluxConduitCastEffect() {
+ super(Outcome.Benefit);
+ staticText = "You may cast any number of spells from your hand without paying their mana costs";
+ }
+
+ private AetherfluxConduitCastEffect(final AetherfluxConduitCastEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public AetherfluxConduitCastEffect copy() {
+ return new AetherfluxConduitCastEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player player = game.getPlayer(source.getControllerId());
+ if (player == null) {
+ return false;
+ }
+ CardUtil.castMultipleWithAttributeForFree(
+ player, source, game, new CardsImpl(player.getHand()), StaticFilters.FILTER_CARD
+ );
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/a/AgentOfTreachery.java b/Mage.Sets/src/mage/cards/a/AgentOfTreachery.java
index 4931519eaac..8c34c1dd047 100644
--- a/Mage.Sets/src/mage/cards/a/AgentOfTreachery.java
+++ b/Mage.Sets/src/mage/cards/a/AgentOfTreachery.java
@@ -2,14 +2,15 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
+import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@@ -24,12 +25,15 @@ import java.util.UUID;
*/
public final class AgentOfTreachery extends CardImpl {
- private static final FilterPermanent filter = new FilterControlledPermanent();
+ private static final FilterPermanent filter = new FilterControlledPermanent("you control three or more permanents you don't own");
static {
filter.add(TargetController.NOT_YOU.getOwnerPredicate());
}
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2);
+ private static final Hint hint = new ValueHint("Permanents you control but don't own", new PermanentsOnBattlefieldCount(filter));
+
public AgentOfTreachery(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
@@ -44,12 +48,7 @@ public final class AgentOfTreachery extends CardImpl {
this.addAbility(ability);
// At the beginning of your end step, if you control three or more permanents you don't own, draw three cards.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfEndStepTriggeredAbility(
- new DrawCardSourceControllerEffect(3)
- ), new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2), "At the beginning of your end step, " +
- "if you control three or more permanents you don't own, draw three cards."
- ).addHint(new ValueHint("Permanents you control but don't own", new PermanentsOnBattlefieldCount(filter))));
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(3)).withInterveningIf(condition).addHint(hint));
}
private AgentOfTreachery(final AgentOfTreachery card) {
diff --git a/Mage.Sets/src/mage/cards/a/AjanisComrade.java b/Mage.Sets/src/mage/cards/a/AjanisComrade.java
index fa08f8af6f3..e00d50924a9 100644
--- a/Mage.Sets/src/mage/cards/a/AjanisComrade.java
+++ b/Mage.Sets/src/mage/cards/a/AjanisComrade.java
@@ -1,32 +1,28 @@
-
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
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.SubType;
import mage.counters.CounterType;
-import mage.filter.common.FilterControlledPermanent;
+import mage.filter.common.FilterControlledPlaneswalkerPermanent;
+
+import java.util.UUID;
/**
- *
* @author fireshoes
*/
public final class AjanisComrade extends CardImpl {
- private static final FilterControlledPermanent filter = new FilterControlledPermanent();
-
- static {
- filter.add(CardType.PLANESWALKER.getPredicate());
- filter.add(SubType.AJANI.getPredicate());
- }
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
+ new FilterControlledPlaneswalkerPermanent(SubType.AJANI, "you control an Ajani planeswalker")
+ );
public AjanisComrade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
@@ -40,10 +36,7 @@ public final class AjanisComrade extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// At the beginning of combat on your turn, if you control an Ajani planeswalker, put a +1/+1 counter on Ajani's Comrade.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())),
- new PermanentsOnTheBattlefieldCondition(filter),
- "At the beginning of combat on your turn, if you control an Ajani planeswalker, put a +1/+1 counter on {this}."));
+ this.addAbility(new BeginningOfCombatTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())).withInterveningIf(condition));
}
private AjanisComrade(final AjanisComrade card) {
diff --git a/Mage.Sets/src/mage/cards/a/AjanisLastStand.java b/Mage.Sets/src/mage/cards/a/AjanisLastStand.java
index a2697f89c90..e6137f7e1d3 100644
--- a/Mage.Sets/src/mage/cards/a/AjanisLastStand.java
+++ b/Mage.Sets/src/mage/cards/a/AjanisLastStand.java
@@ -1,51 +1,42 @@
package mage.cards.a;
-import java.util.UUID;
-
-import mage.MageObject;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.DiscardedByOpponentTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.costs.common.SacrificeSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
+import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.token.AvatarToken2;
+import java.util.UUID;
+
/**
- *
* @author TheElk801
*/
public final class AjanisLastStand extends CardImpl {
- private static final FilterControlledPermanent filter = new FilterControlledPermanent();
-
- static {
- filter.add(SubType.PLAINS.getPredicate());
- }
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
+ new FilterControlledPermanent(SubType.PLAINS, "you control a Plains")
+ );
public AjanisLastStand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}");
// Whenever a creature or planeswalker you control dies, you may sacrifice Ajani's Last Stand. If you do, create a 4/4 white Avatar creature token with flying.
- this.addAbility(new AjanisLastStandTriggeredAbility());
+ this.addAbility(new DiesCreatureTriggeredAbility(
+ new DoIfCostPaid(new CreateTokenEffect(new AvatarToken2()), new SacrificeSourceCost()),
+ false, StaticFilters.FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER
+ ));
// When a spell or ability an opponent controls causes you to discard this card, if you control a Plains, create a 4/4 white Avatar creature token with flying.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new DiscardedByOpponentTriggeredAbility(new CreateTokenEffect(new AvatarToken2())),
- new PermanentsOnTheBattlefieldCondition(filter),
- "When a spell or ability an opponent controls causes you to discard this card, "
- + "if you control a Plains, create a 4/4 white Avatar creature token with flying."
- ));
+ this.addAbility(new DiscardedByOpponentTriggeredAbility(new CreateTokenEffect(new AvatarToken2())).withInterveningIf(condition));
}
private AjanisLastStand(final AjanisLastStand card) {
@@ -57,53 +48,3 @@ public final class AjanisLastStand extends CardImpl {
return new AjanisLastStand(this);
}
}
-
-class AjanisLastStandTriggeredAbility extends TriggeredAbilityImpl {
-
- public AjanisLastStandTriggeredAbility() {
- super(Zone.BATTLEFIELD, new DoIfCostPaid(
- new CreateTokenEffect(new AvatarToken2()),
- new SacrificeSourceCost()
- ), false);
- setLeavesTheBattlefieldTrigger(true);
- }
-
- private AjanisLastStandTriggeredAbility(final AjanisLastStandTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public AjanisLastStandTriggeredAbility copy() {
- return new AjanisLastStandTriggeredAbility(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.isDiesEvent()) {
- if (zEvent.getTarget().isControlledBy(controllerId)
- && (zEvent.getTarget().isCreature(game)
- || zEvent.getTarget().isPlaneswalker(game))) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public String getRule() {
- return "Whenever a creature or planeswalker you control dies, "
- + "you may sacrifice {this}. "
- + "If you do, create a 4/4 white Avatar creature token with flying.";
- }
-
- @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/a/AlchemistsTalent.java b/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java
index 606b16c5bb1..65dfb59a6c2 100644
--- a/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java
+++ b/Mage.Sets/src/mage/cards/a/AlchemistsTalent.java
@@ -7,7 +7,6 @@ import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
@@ -52,18 +51,24 @@ public final class AlchemistsTalent extends CardImpl {
// Treasures you control have "{T}, Sacrifice this artifact: Add two mana of any one color."
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(2), new TapSourceCost());
ability.addCost(new SacrificeSourceCost().setText("sacrifice this artifact"));
- this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new GainAbilityControlledEffect(ability, Duration.WhileOnBattlefield, new FilterPermanent(SubType.TREASURE, "Treasures")), 2)));
+ this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(
+ new GainAbilityControlledEffect(
+ ability, Duration.WhileOnBattlefield,
+ new FilterPermanent(SubType.TREASURE, "Treasures")
+ ), 2
+ )));
// {4}{R}: Level 3
this.addAbility(new ClassLevelAbility(3, "{4}{R}"));
// Whenever you cast a spell, if mana from a Treasure was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent.
- this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new ConditionalInterveningIfTriggeredAbility(
+ this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(
new SpellCastControllerTriggeredAbility(
- new DamagePlayersEffect(AlchemistsTalentValue.instance, TargetController.OPPONENT), StaticFilters.FILTER_SPELL, false, SetTargetPointer.SPELL
- ), AlchemistsTalentCondition.instance, "Whenever you cast a spell, if mana from a Treasure " +
- "was spent to cast it, this Class deals damage equal to that spell's mana value to each opponent"
- ), 3)));
+ new DamagePlayersEffect(AlchemistsTalentValue.instance, TargetController.OPPONENT)
+ .setText("{this} deals damage equal to that spell's mana value to each opponent"),
+ StaticFilters.FILTER_SPELL, false, SetTargetPointer.SPELL
+ ).withInterveningIf(AlchemistsTalentCondition.instance), 3
+ )));
}
private AlchemistsTalent(final AlchemistsTalent card) {
@@ -84,6 +89,11 @@ enum AlchemistsTalentCondition implements Condition {
Spell spell = (Spell) source.getEffects().get(0).getValue("spellCast");
return spell != null && ManaPaidSourceWatcher.getTreasurePaid(spell.getSourceId(), game) > 0;
}
+
+ @Override
+ public String toString() {
+ return "mana from a Treasure was spent to cast it";
+ }
}
enum AlchemistsTalentValue implements DynamicValue {
@@ -111,6 +121,6 @@ enum AlchemistsTalentValue implements DynamicValue {
@Override
public String toString() {
- return "";
+ return "1";
}
}
diff --git a/Mage.Sets/src/mage/cards/a/AlelaCunningConqueror.java b/Mage.Sets/src/mage/cards/a/AlelaCunningConqueror.java
index 35a70741ddc..64e623d1928 100644
--- a/Mage.Sets/src/mage/cards/a/AlelaCunningConqueror.java
+++ b/Mage.Sets/src/mage/cards/a/AlelaCunningConqueror.java
@@ -14,7 +14,7 @@ import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.permanent.token.FaerieRogueToken;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -48,7 +48,7 @@ public final class AlelaCunningConqueror extends CardImpl {
Effect effect = new GoadTargetEffect().setText("goad target creature that player controls");
Ability ability = new OneOrMoreCombatDamagePlayerTriggeredAbility(Zone.BATTLEFIELD, effect, faerieFilter, SetTargetPointer.PLAYER, false);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/AlistairTheBrigadier.java b/Mage.Sets/src/mage/cards/a/AlistairTheBrigadier.java
index 0f5254018f9..1bb1e497add 100644
--- a/Mage.Sets/src/mage/cards/a/AlistairTheBrigadier.java
+++ b/Mage.Sets/src/mage/cards/a/AlistairTheBrigadier.java
@@ -18,9 +18,8 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
-import mage.filter.FilterSpell;
+import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
-import mage.filter.common.FilterHistoricSpell;
import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.game.permanent.token.SoldierToken;
@@ -31,7 +30,6 @@ import java.util.UUID;
*/
public final class AlistairTheBrigadier extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
private static final FilterPermanent filter2 = new FilterControlledPermanent("historic permanents you control");
static {
@@ -52,7 +50,7 @@ public final class AlistairTheBrigadier extends CardImpl {
// Whenever you cast a historic spell, create a 1/1 white Soldier creature token.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new CreateTokenEffect(new SoldierToken()), filter, false
+ new CreateTokenEffect(new SoldierToken()), StaticFilters.FILTER_SPELL_HISTORIC, false
));
// Whenever Alistair attacks, you may pay {8}. If you do, creatures you control get +X/+X until end of turn, where X is the number of historic permanents you control.
diff --git a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java
index 42bbe7073ef..f33df1df178 100644
--- a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java
+++ b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java
@@ -2,11 +2,11 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.TriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.KickedCostCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.abilities.keyword.KickerAbility;
import mage.cards.CardImpl;
@@ -35,6 +35,9 @@ public final class AnaBattlemage extends CardImpl {
filter.add(TappedPredicate.UNTAPPED);
}
+ private static final Condition condition = new KickedCostCondition("{2}{U}");
+ private static final Condition condition2 = new KickedCostCondition("{1}{B}");
+
public AnaBattlemage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
this.subtype.add(SubType.HUMAN);
@@ -46,16 +49,17 @@ public final class AnaBattlemage extends CardImpl {
KickerAbility kickerAbility = new KickerAbility("{2}{U}");
kickerAbility.addKickerCost("{1}{B}");
this.addAbility(kickerAbility);
+
// When Ana Battlemage enters the battlefield, if it was kicked with its {2}{U} kicker, target player discards three cards.
- TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(3));
+ Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(3)).withInterveningIf(condition);
ability.addTarget(new TargetPlayer());
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{2}{U}"),
- "When {this} enters, if it was kicked with its {2}{U} kicker, target player discards three cards."));
+ this.addAbility(ability);
+
// When Ana Battlemage enters the battlefield, if it was kicked with its {1}{B} kicker, tap target untapped creature and that creature deals damage equal to its power to its controller.
- ability = new EntersBattlefieldTriggeredAbility(new AnaBattlemageKickerEffect());
+ ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()).withInterveningIf(condition2);
+ ability.addEffect(new AnaBattlemageEffect());
ability.addTarget(new TargetCreaturePermanent(filter));
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new KickedCostCondition("{1}{B}"),
- "When {this} enters, if it was kicked with its {1}{B} kicker, tap target untapped creature and that creature deals damage equal to its power to its controller."));
+ this.addAbility(ability);
}
private AnaBattlemage(final AnaBattlemage card) {
@@ -68,34 +72,31 @@ public final class AnaBattlemage extends CardImpl {
}
}
-class AnaBattlemageKickerEffect extends OneShotEffect {
+class AnaBattlemageEffect extends OneShotEffect {
- AnaBattlemageKickerEffect() {
+ AnaBattlemageEffect() {
super(Outcome.Detriment);
- this.staticText = "tap target untapped creature and it deals damage equal to its power to its controller";
+ this.staticText = "and it deals damage equal to its power to its controller";
}
- private AnaBattlemageKickerEffect(final AnaBattlemageKickerEffect effect) {
+ private AnaBattlemageEffect(final AnaBattlemageEffect effect) {
super(effect);
}
@Override
- public AnaBattlemageKickerEffect copy() {
- return new AnaBattlemageKickerEffect(this);
+ public AnaBattlemageEffect copy() {
+ return new AnaBattlemageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
- boolean applied = false;
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
- if (targetCreature != null) {
- applied = targetCreature.tap(source, game);
- Player controller = game.getPlayer(targetCreature.getControllerId());
- if (controller != null) {
- controller.damage(targetCreature.getPower().getValue(), source.getSourceId(), source, game);
- applied = true;
- }
+ if (targetCreature == null) {
+ return false;
}
- return applied;
+ Player controller = game.getPlayer(targetCreature.getControllerId());
+ return controller != null && controller.damage(
+ targetCreature.getPower().getValue(), source.getSourceId(), source, game
+ ) > 0;
}
}
diff --git a/Mage.Sets/src/mage/cards/a/AngelOfDestiny.java b/Mage.Sets/src/mage/cards/a/AngelOfDestiny.java
index c1c14a34957..bf0df6ed71b 100644
--- a/Mage.Sets/src/mage/cards/a/AngelOfDestiny.java
+++ b/Mage.Sets/src/mage/cards/a/AngelOfDestiny.java
@@ -3,13 +3,12 @@ package mage.cards.a;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
import mage.abilities.condition.common.MoreThanStartingLifeTotalCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@@ -47,13 +46,8 @@ public final class AngelOfDestiny extends CardImpl {
));
// At the beginning of your end step, if you have at least 15 life more than your starting life total, each player Angel of Destiny attacked this turn loses the game.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfEndStepTriggeredAbility(
- new AngelOfDestinyLoseEffect()
- ), MoreThanStartingLifeTotalCondition.FIFTEEN, "At the beginning of your end step, " +
- "if you have at least 15 life more than your starting life total, " +
- "each player {this} attacked this turn loses the game."
- ), new AngelOfDestinyWatcher());
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new AngelOfDestinyLoseEffect())
+ .withInterveningIf(MoreThanStartingLifeTotalCondition.FIFTEEN), new AngelOfDestinyWatcher());
}
private AngelOfDestiny(final AngelOfDestiny card) {
@@ -101,6 +95,7 @@ class AngelOfDestinyLoseEffect extends OneShotEffect {
AngelOfDestinyLoseEffect() {
super(Outcome.Benefit);
+ staticText = "each player {this} attacked this turn loses the game";
}
private AngelOfDestinyLoseEffect(final AngelOfDestinyLoseEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/a/AngelicSellSword.java b/Mage.Sets/src/mage/cards/a/AngelicSellSword.java
index b7028153417..380bf6633cf 100644
--- a/Mage.Sets/src/mage/cards/a/AngelicSellSword.java
+++ b/Mage.Sets/src/mage/cards/a/AngelicSellSword.java
@@ -6,7 +6,6 @@ import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.FlyingAbility;
@@ -48,11 +47,8 @@ public final class AngelicSellSword extends CardImpl {
));
// Whenever Angelic Sell-Sword attacks, if its power is 6 or greater, draw a card.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1)),
- AngelicSellSwordCondition.instance, "Whenever {this} attacks, " +
- "if its power is 6 or greater, draw a card."
- ));
+ this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1))
+ .withInterveningIf(AngelicSellSwordCondition.instance));
}
private AngelicSellSword(final AngelicSellSword card) {
@@ -76,4 +72,9 @@ enum AngelicSellSwordCondition implements Condition {
.map(MageInt::getValue)
.orElse(0) >= 6;
}
+
+ @Override
+ public String toString() {
+ return "its power is 6 or greater";
+ }
}
diff --git a/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java b/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java
index 42571f0ebf6..9f4ae930dc2 100644
--- a/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java
+++ b/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java
@@ -1,50 +1,45 @@
-
package mage.cards.a;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
+import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
/**
- *
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public final class ApothecaryGeist extends CardImpl {
-
- private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Elf");
+
+ private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SPIRIT, "you control another Spirit");
static {
filter.add(AnotherPredicate.instance);
- filter.add(SubType.SPIRIT.getPredicate());
}
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter);
+
public ApothecaryGeist(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
-
+
// When Apothecary Geist enters the battlefield, if you control another Spirit, you gain 3 life.
- TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3));
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- triggeredAbility,
- new PermanentsOnTheBattlefieldCondition(filter),
- "When {this} enters, if you control another Spirit, you gain 3 life."));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)).withInterveningIf(condition));
}
private ApothecaryGeist(final ApothecaryGeist card) {
diff --git a/Mage.Sets/src/mage/cards/a/ArcaneProxy.java b/Mage.Sets/src/mage/cards/a/ArcaneProxy.java
index 60319104e0f..c986b141b14 100644
--- a/Mage.Sets/src/mage/cards/a/ArcaneProxy.java
+++ b/Mage.Sets/src/mage/cards/a/ArcaneProxy.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.ExileTargetCardCopyAndCastEffect;
import mage.abilities.keyword.PrototypeAbility;
import mage.cards.CardImpl;
@@ -42,12 +41,11 @@ public final class ArcaneProxy extends CardImpl {
this.addAbility(new PrototypeAbility(this, "{1}{U}{U}", 2, 1));
// When Arcane Proxy enters the battlefield, if you cast it, exile target instant or sorcery card with mana value less than or equal to Arcane Proxy's power from your graveyard. Copy that card. You may cast the copy without paying its mana cost.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new ExileTargetCardCopyAndCastEffect(true)),
- CastFromEverywhereSourceCondition.instance, "When {this} enters, " +
- "if you cast it, exile target instant or sorcery card with mana value less than or equal to {this}'s " +
- "power from your graveyard. Copy that card. You may cast the copy without paying its mana cost."
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(
+ new ExileTargetCardCopyAndCastEffect(true)
+ .setText("exile target instant or sorcery card with mana value less than or equal to {this}'s " +
+ "power from your graveyard. Copy that card. You may cast the copy without paying its mana cost")
+ ).withInterveningIf(CastFromEverywhereSourceCondition.instance);
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/ArchangelOfWrath.java b/Mage.Sets/src/mage/cards/a/ArchangelOfWrath.java
index aa663cf4f2f..f472cff0b5a 100644
--- a/Mage.Sets/src/mage/cards/a/ArchangelOfWrath.java
+++ b/Mage.Sets/src/mage/cards/a/ArchangelOfWrath.java
@@ -1,10 +1,9 @@
package mage.cards.a;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.KickerAbility;
@@ -40,19 +39,19 @@ public final class ArchangelOfWrath extends CardImpl {
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
- TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2));
- triggeredAbility.addTarget(new TargetAnyTarget());
// When Archangel of Wrath enters the battlefield, if it was kicked, it deals 2 damage to any target.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- triggeredAbility, KickedCondition.ONCE, "When {this} enters, " +
- "if it was kicked, it deals 2 damage to any target."
- ));
+ Ability ability = new EntersBattlefieldTriggeredAbility(
+ new DamageTargetEffect(2, "it")
+ ).withInterveningIf(KickedCondition.ONCE);
+ ability.addTarget(new TargetAnyTarget());
+ this.addAbility(ability);
// When Archangel of Wrath enters the battlefield, if it was kicked twice, it deals 2 damage to any target.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- triggeredAbility.copy(), KickedCondition.TWICE, "When {this} enters, " +
- "if it was kicked twice, it deals 2 damage to any target."
- ));
+ ability = new EntersBattlefieldTriggeredAbility(
+ new DamageTargetEffect(2, "it")
+ ).withInterveningIf(KickedCondition.TWICE);
+ ability.addTarget(new TargetAnyTarget());
+ this.addAbility(ability);
}
private ArchangelOfWrath(final ArchangelOfWrath card) {
diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfTheDross.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfTheDross.java
index d3583388e8f..4f44292aeb8 100644
--- a/Mage.Sets/src/mage/cards/a/ArchfiendOfTheDross.java
+++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfTheDross.java
@@ -2,7 +2,6 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.condition.Condition;
@@ -13,9 +12,11 @@ import mage.abilities.effects.common.LoseGameSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
@@ -33,7 +34,7 @@ import java.util.UUID;
*/
public final class ArchfiendOfTheDross extends CardImpl {
- private static final Condition condition = new SourceHasCounterCondition(CounterType.OIL, 0, 0);
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.OIL, ComparisonType.EQUAL_TO, 0);
public ArchfiendOfTheDross(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}");
diff --git a/Mage.Sets/src/mage/cards/a/ArchivistOfGondor.java b/Mage.Sets/src/mage/cards/a/ArchivistOfGondor.java
index dc042152bab..14b7f10242a 100644
--- a/Mage.Sets/src/mage/cards/a/ArchivistOfGondor.java
+++ b/Mage.Sets/src/mage/cards/a/ArchivistOfGondor.java
@@ -1,12 +1,13 @@
package mage.cards.a;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.effects.common.BecomesMonarchSourceEffect;
import mage.abilities.effects.common.DrawCardTargetEffect;
import mage.abilities.hint.common.MonarchHint;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -15,6 +16,7 @@ import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.CommanderPredicate;
+import mage.game.Game;
import java.util.UUID;
@@ -39,13 +41,11 @@ public final class ArchivistOfGondor extends CardImpl {
this.toughness = new MageInt(3);
// When your commander deals combat damage to a player, if there is no monarch, you become the monarch.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new DealsDamageToAPlayerAllTriggeredAbility(
- new BecomesMonarchSourceEffect(), filter, false,
- SetTargetPointer.NONE, true
- ), (game, source) -> game.getMonarchId() == null, "When your commander " +
- "deals combat damage to a player, if there is no monarch, you become the monarch."
- ).addHint(MonarchHint.instance));
+ this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(
+ new BecomesMonarchSourceEffect(), filter, false,
+ SetTargetPointer.NONE, true
+ ).setTriggerPhrase("When your commander deals combat damage to a player, ")
+ .withInterveningIf(ArchivistOfGondorCondition.instance).addHint(MonarchHint.instance));
// At the beginning of the monarch's end step, that player draws a card.
this.addAbility(new BeginningOfEndStepTriggeredAbility(
@@ -62,3 +62,17 @@ public final class ArchivistOfGondor extends CardImpl {
return new ArchivistOfGondor(this);
}
}
+
+enum ArchivistOfGondorCondition implements Condition {
+ instance;
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ return game.getMonarchId() == null;
+ }
+
+ @Override
+ public String toString() {
+ return "there is no monarch";
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java
index 76c4e4c2f31..2ae3ec86cfd 100644
--- a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java
+++ b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java
@@ -1,12 +1,11 @@
package mage.cards.a;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@@ -30,12 +29,9 @@ public final class ArchmageAscension extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
// At the beginning of each end step, if you drew two or more cards this turn, you may put a quest counter on Archmage Ascension.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfEndStepTriggeredAbility(
- TargetController.EACH_PLAYER, new AddCountersSourceEffect(CounterType.QUEST.createInstance(1)),
- true
- ), ArchmageAscensionCondition.instance, "At the beginning of each end step, " +
- "if you drew two or more cards this turn, you may put a quest counter on {this}."
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.EACH_PLAYER, new AddCountersSourceEffect(CounterType.QUEST.createInstance()),
+ true, ArchmageAscensionCondition.instance
), new CardsAmountDrawnThisTurnWatcher());
// As long as Archmage Ascension has six or more quest counters on it, if you would draw a card,
@@ -61,6 +57,11 @@ enum ArchmageAscensionCondition implements Condition {
CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class);
return watcher != null && watcher.getAmountCardsDrawn(source.getControllerId()) >= 2;
}
+
+ @Override
+ public String toString() {
+ return "you drew two or more cards this turn";
+ }
}
class ArchmageAscensionReplacementEffect extends ReplacementEffectImpl {
diff --git a/Mage.Sets/src/mage/cards/a/ArchpriestOfIona.java b/Mage.Sets/src/mage/cards/a/ArchpriestOfIona.java
index dc165494fb4..8409984d5d9 100644
--- a/Mage.Sets/src/mage/cards/a/ArchpriestOfIona.java
+++ b/Mage.Sets/src/mage/cards/a/ArchpriestOfIona.java
@@ -2,19 +2,20 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.FullPartyCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.PartyCount;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect;
import mage.abilities.hint.common.PartyCountHint;
import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
@@ -35,19 +36,16 @@ public final class ArchpriestOfIona extends CardImpl {
// Archpriest of Iona's power is equal to the number of creatures in your party.
this.addAbility(new SimpleStaticAbility(
Zone.ALL,
- new SetBasePowerSourceEffect(
- PartyCount.instance
- ).setText("{this}'s power is equal to the number of creatures in your party. " + PartyCount.getReminder())
+ new SetBasePowerSourceEffect(PartyCount.instance)
+ .setText("{this}'s power is equal to the number of creatures in your party. " + PartyCount.getReminder())
).addHint(PartyCountHint.instance));
// At the beginning of combat on your turn, if you have a full party, target creature gets +1/+1 and gains flying until end of turn.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- new BoostTargetEffect(1, 1, Duration.EndOfTurn)
- ), FullPartyCondition.instance, "At the beginning of combat on your turn, " +
- "if you have a full party, target creature gets +1/+1 and gains flying until end of turn."
- );
- ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn));
+ Ability ability = new BeginningOfCombatTriggeredAbility(
+ new BoostTargetEffect(1, 1).setText("target creature gets +1/+1")
+ ).withInterveningIf(FullPartyCondition.instance);
+ ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance())
+ .setText("and gains flying until end of turn"));
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java
index e4000613e0f..2332e95e80d 100644
--- a/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java
+++ b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java
@@ -2,18 +2,18 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
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.GameEvent;
import mage.game.stack.Spell;
+import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.HashMap;
@@ -39,17 +39,10 @@ public final class ArclightPhoenix extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// At the beginning of combat on your turn, if you cast 3 or more instants and/or sorceries this turn, return Arclight Phoenix from your graveyard to the battlefield.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- Zone.GRAVEYARD,
- TargetController.YOU, new ReturnSourceFromGraveyardToBattlefieldEffect(),
- false
- ), ArclightPhoenixCondition.instance,
- "At the beginning of combat on your turn, "
- + "if you've cast three or more instant "
- + "and sorcery spells this turn, return {this} "
- + "from your graveyard to the battlefield."
- ), new ArclightPhoenixWatcher());
+ this.addAbility(new BeginningOfCombatTriggeredAbility(
+ Zone.GRAVEYARD, TargetController.YOU,
+ new ReturnSourceFromGraveyardToBattlefieldEffect(), false
+ ).withInterveningIf(ArclightPhoenixCondition.instance), new ArclightPhoenixWatcher());
}
private ArclightPhoenix(final ArclightPhoenix card) {
@@ -67,8 +60,12 @@ enum ArclightPhoenixCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
- ArclightPhoenixWatcher watcher = game.getState().getWatcher(ArclightPhoenixWatcher.class);
- return watcher != null && watcher.getInstantSorceryCount(source.getControllerId()) > 2;
+ return ArclightPhoenixWatcher.getInstantSorceryCount(game, source);
+ }
+
+ @Override
+ public String toString() {
+ return "you've cast three or more instant and sorcery spells this turn";
}
}
@@ -82,15 +79,12 @@ class ArclightPhoenixWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
- if (event.getType() == GameEvent.EventType.SPELL_CAST) {
- Spell spell = game.getStack().getSpell(event.getTargetId());
- if (spell == null || !spell.isInstantOrSorcery(game)) {
- return;
- }
- this.instantSorceryCount.putIfAbsent(spell.getControllerId(), 0);
- this.instantSorceryCount.compute(
- spell.getControllerId(), (k, a) -> a + 1
- );
+ if (event.getType() != GameEvent.EventType.SPELL_CAST) {
+ return;
+ }
+ Spell spell = game.getStack().getSpell(event.getTargetId());
+ if (spell != null && spell.isInstantOrSorcery(game)) {
+ this.instantSorceryCount.compute(spell.getControllerId(), CardUtil::setOrIncrementValue);
}
}
@@ -100,7 +94,11 @@ class ArclightPhoenixWatcher extends Watcher {
this.instantSorceryCount.clear();
}
- int getInstantSorceryCount(UUID playerId) {
- return this.instantSorceryCount.getOrDefault(playerId, 0);
+ static boolean getInstantSorceryCount(Game game, Ability source) {
+ return game
+ .getState()
+ .getWatcher(ArclightPhoenixWatcher.class)
+ .instantSorceryCount
+ .getOrDefault(source.getControllerId(), 0) >= 3;
}
}
diff --git a/Mage.Sets/src/mage/cards/a/ArcumDagsson.java b/Mage.Sets/src/mage/cards/a/ArcumDagsson.java
index 4bf9142e155..82a5bfb9ee0 100644
--- a/Mage.Sets/src/mage/cards/a/ArcumDagsson.java
+++ b/Mage.Sets/src/mage/cards/a/ArcumDagsson.java
@@ -12,7 +12,7 @@ import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import mage.target.TargetPermanent;
import mage.target.common.TargetCardInLibrary;
@@ -22,9 +22,10 @@ import mage.target.common.TargetCardInLibrary;
*/
public final class ArcumDagsson extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard("noncreature artifact card");
+ private static final FilterCard filter = new FilterCard("noncreature artifact card");
static {
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
filter.add(CardType.ARTIFACT.getPredicate());
}
diff --git a/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java
index a05326bb38e..291e5a65642 100644
--- a/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java
+++ b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java
@@ -29,8 +29,7 @@ import java.util.UUID;
*/
public final class ArixmethesSlumberingIsle extends CardImpl {
- private static final Condition condition
- = new SourceHasCounterCondition(CounterType.SLUMBER, 1, Integer.MAX_VALUE);
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.SLUMBER);
public ArixmethesSlumberingIsle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}");
diff --git a/Mage.Sets/src/mage/cards/a/ArmWithAether.java b/Mage.Sets/src/mage/cards/a/ArmWithAether.java
index 5c8eacb5aac..56864b7214a 100644
--- a/Mage.Sets/src/mage/cards/a/ArmWithAether.java
+++ b/Mage.Sets/src/mage/cards/a/ArmWithAether.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -30,7 +30,7 @@ public final class ArmWithAether extends CardImpl {
// Until end of turn, creatures you control gain "Whenever this creature deals damage to an opponent, you may return target creature that player controls to its owner's hand."
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
Effect effect = new GainAbilityControlledEffect(ability, Duration.EndOfTurn, new FilterCreaturePermanent());
effect.setText("Until end of turn, creatures you control gain \"Whenever this creature deals damage to an opponent, you may return target creature that player controls to its owner's hand.\"");
diff --git a/Mage.Sets/src/mage/cards/a/ArmoryGuard.java b/Mage.Sets/src/mage/cards/a/ArmoryGuard.java
index 6b20c41adaa..ea8a354fc45 100644
--- a/Mage.Sets/src/mage/cards/a/ArmoryGuard.java
+++ b/Mage.Sets/src/mage/cards/a/ArmoryGuard.java
@@ -1,9 +1,9 @@
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
@@ -12,25 +12,19 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
-import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledPermanent;
+
+import java.util.UUID;
/**
- *
* @author jeffwadsworth
*/
public final class ArmoryGuard extends CardImpl {
-
- private static final String rule = "Armory Guard has vigilance as long as you control a Gate";
-
- private static final FilterPermanent filter = new FilterPermanent("Gate");
-
- static {
- filter.add(SubType.GATE.getPredicate());
- }
+
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(SubType.GATE));
public ArmoryGuard(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.GIANT);
this.subtype.add(SubType.SOLDIER);
@@ -38,8 +32,10 @@ public final class ArmoryGuard extends CardImpl {
this.toughness = new MageInt(5);
// Armory Guard has vigilance as long as you control a Gate.
- ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(VigilanceAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), rule);
- this.addAbility(new SimpleStaticAbility(effect));
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
+ new GainAbilitySourceEffect(VigilanceAbility.getInstance()),
+ condition, "{this} has vigilance as long as you control a Gate"
+ )));
}
private ArmoryGuard(final ArmoryGuard card) {
diff --git a/Mage.Sets/src/mage/cards/a/ArrogantOutlaw.java b/Mage.Sets/src/mage/cards/a/ArrogantOutlaw.java
index fd815efc8d8..434a8048025 100644
--- a/Mage.Sets/src/mage/cards/a/ArrogantOutlaw.java
+++ b/Mage.Sets/src/mage/cards/a/ArrogantOutlaw.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.OpponentsLostLifeCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.hint.common.OpponentsLostLifeHint;
@@ -29,13 +28,10 @@ public final class ArrogantOutlaw extends CardImpl {
this.toughness = new MageInt(2);
// When Arrogant Outlaw enters the battlefield, if an opponent lost life this turn, each opponent loses 2 life and you gain 2 life.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(
- new LoseLifeOpponentsEffect(2), false
- ), OpponentsLostLifeCondition.instance, "When {this} enters, " +
- "if an opponent lost life this turn, each opponent loses 2 life and you gain 2 life."
- );
- ability.addEffect(new GainLifeEffect(2));
+ Ability ability = new EntersBattlefieldTriggeredAbility(
+ new LoseLifeOpponentsEffect(2), false
+ ).withInterveningIf(OpponentsLostLifeCondition.instance);
+ ability.addEffect(new GainLifeEffect(2).concatBy("and"));
this.addAbility(ability.addHint(OpponentsLostLifeHint.instance));
}
diff --git a/Mage.Sets/src/mage/cards/a/ArtifactBlast.java b/Mage.Sets/src/mage/cards/a/ArtifactBlast.java
index 7de47c81c49..f1a79cc3ac8 100644
--- a/Mage.Sets/src/mage/cards/a/ArtifactBlast.java
+++ b/Mage.Sets/src/mage/cards/a/ArtifactBlast.java
@@ -1,24 +1,30 @@
-
package mage.cards.a;
-import java.util.UUID;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.filter.common.FilterArtifactSpell;
+import mage.filter.FilterSpell;
import mage.target.TargetSpell;
+import java.util.UUID;
+
/**
*
* @author Jgod
*/
public final class ArtifactBlast extends CardImpl {
+
+ private static final FilterSpell filter = new FilterSpell("artifact spell");
+ static {
+ filter.add(CardType.ARTIFACT.getPredicate());
+ }
+
public ArtifactBlast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}");
// Counter target artifact spell.
- this.getSpellAbility().addTarget(new TargetSpell(new FilterArtifactSpell()));
+ this.getSpellAbility().addTarget(new TargetSpell(filter));
this.getSpellAbility().addEffect(new CounterTargetEffect());
}
diff --git a/Mage.Sets/src/mage/cards/a/ArtistsTalent.java b/Mage.Sets/src/mage/cards/a/ArtistsTalent.java
index 6e7235eb89c..3eb826b7ab6 100644
--- a/Mage.Sets/src/mage/cards/a/ArtistsTalent.java
+++ b/Mage.Sets/src/mage/cards/a/ArtistsTalent.java
@@ -19,7 +19,7 @@ import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
@@ -33,7 +33,11 @@ import java.util.UUID;
*/
public final class ArtistsTalent extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard("noncreature spells");
+ private static final FilterCard filter = new FilterCard("noncreature spells");
+
+ static {
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
+ }
public ArtistsTalent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}");
diff --git a/Mage.Sets/src/mage/cards/a/AsajjVentress.java b/Mage.Sets/src/mage/cards/a/AsajjVentress.java
index 139d20b5f30..4384a66cd0b 100644
--- a/Mage.Sets/src/mage/cards/a/AsajjVentress.java
+++ b/Mage.Sets/src/mage/cards/a/AsajjVentress.java
@@ -1,13 +1,11 @@
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.BecomesBlockedSourceTriggeredAbility;
import mage.abilities.condition.common.HateCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.BlockingCreatureCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.combat.BlocksIfAbleTargetEffect;
@@ -15,13 +13,12 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect;
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.constants.*;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.LifeLossOtherFromCombatWatcher;
+import java.util.UUID;
+
/**
* @author Styxo
*/
@@ -43,10 +40,8 @@ public final class AsajjVentress extends CardImpl {
this.addAbility(new BecomesBlockedSourceTriggeredAbility(effect, false));
// Hate — Whenever Asajj Ventress attacks, if an opponent lost life from a source other than combat damage this turn, target creature blocks this turn if able.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new BlocksIfAbleTargetEffect(Duration.EndOfTurn), false),
- HateCondition.instance,
- "Hate — Whenever Asajj Ventress attacks, if an opponent lost life from a source other than combat damage this turn, target creature blocks this turn if able");
+ Ability ability = new AttacksTriggeredAbility(new BlocksIfAbleTargetEffect(Duration.EndOfTurn), false)
+ .withInterveningIf(HateCondition.instance).setAbilityWord(AbilityWord.HATE);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability, new LifeLossOtherFromCombatWatcher());
}
diff --git a/Mage.Sets/src/mage/cards/a/AshPartyCrasher.java b/Mage.Sets/src/mage/cards/a/AshPartyCrasher.java
index 7deb6eea062..6736bad9f80 100644
--- a/Mage.Sets/src/mage/cards/a/AshPartyCrasher.java
+++ b/Mage.Sets/src/mage/cards/a/AshPartyCrasher.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.condition.common.CelebrationCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
@@ -36,11 +35,8 @@ public final class AshPartyCrasher extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// Celebration -- Whenever Ash, Party Crasher attacks, if two or more nonland permanents entered the battlefield under your control this turn, put a +1/+1 counter on Ash.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), false),
- CelebrationCondition.instance, "Whenever {this} attacks, if two or more nonland permanents " +
- "entered the battlefield under your control this turn, put a +1/+1 counter on {this}."
- );
+ Ability ability = new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), false)
+ .withInterveningIf(CelebrationCondition.instance);
ability.setAbilityWord(AbilityWord.CELEBRATION);
ability.addHint(CelebrationCondition.getHint());
this.addAbility(ability, new PermanentsEnteredBattlefieldWatcher());
diff --git a/Mage.Sets/src/mage/cards/a/AshlingTheExtinguisher.java b/Mage.Sets/src/mage/cards/a/AshlingTheExtinguisher.java
index 87c9ed6ce85..3b110555383 100644
--- a/Mage.Sets/src/mage/cards/a/AshlingTheExtinguisher.java
+++ b/Mage.Sets/src/mage/cards/a/AshlingTheExtinguisher.java
@@ -11,7 +11,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -32,7 +32,7 @@ public final class AshlingTheExtinguisher extends CardImpl {
Effect effect = new SacrificeTargetEffect().setText("choose target creature that player controls. The player sacrifices that creature");
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetCreaturePermanent());
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java
index 558a2ecc4bf..3d01de1043e 100644
--- a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java
+++ b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java
@@ -2,14 +2,13 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeSourceControllerEffect;
import mage.abilities.keyword.MadnessAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -24,6 +23,8 @@ import java.util.UUID;
*/
public final class AsylumVisitor extends CardImpl {
+ private static final Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0, TargetController.ACTIVE);
+
public AsylumVisitor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
this.subtype.add(SubType.VAMPIRE);
@@ -32,12 +33,10 @@ public final class AsylumVisitor extends CardImpl {
this.toughness = new MageInt(1);
// At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(TargetController.ANY, new DrawCardSourceControllerEffect(1, true), false),
- new CardsInHandCondition(ComparisonType.EQUAL_TO, 0, TargetController.ACTIVE),
- "At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life.");
- Effect effect = new LoseLifeSourceControllerEffect(1);
- ability.addEffect(effect);
+ Ability ability = new BeginningOfUpkeepTriggeredAbility(
+ TargetController.ANY, new DrawCardSourceControllerEffect(1, true), false
+ ).withInterveningIf(condition);
+ ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and"));
this.addAbility(ability);
// Madness {1}{B}
diff --git a/Mage.Sets/src/mage/cards/a/AttendantOfVraska.java b/Mage.Sets/src/mage/cards/a/AttendantOfVraska.java
index d4f6dd732c7..fd25f2b0cc8 100644
--- a/Mage.Sets/src/mage/cards/a/AttendantOfVraska.java
+++ b/Mage.Sets/src/mage/cards/a/AttendantOfVraska.java
@@ -2,32 +2,26 @@ package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.DiesSourceTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.TargetController;
-import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledPlaneswalkerPermanent;
import java.util.UUID;
/**
- *
* @author TheElk801
*/
public final class AttendantOfVraska extends CardImpl {
- private static final FilterPermanent filter = new FilterPermanent("a Vraska planeswalker");
-
- static {
- filter.add(TargetController.YOU.getControllerPredicate());
- filter.add(CardType.PLANESWALKER.getPredicate());
- filter.add(SubType.VRASKA.getPredicate());
- }
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
+ new FilterControlledPlaneswalkerPermanent(SubType.VRASKA, "you control a Vraska planeswalker")
+ );
public AttendantOfVraska(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}");
@@ -38,13 +32,8 @@ public final class AttendantOfVraska extends CardImpl {
this.toughness = new MageInt(3);
// When Attendant of Vraska dies, if you control a Vraska planeswalker, you gain life equal to Attendant of Vraska's power.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new DiesSourceTriggeredAbility(new GainLifeEffect(
- SourcePermanentPowerValue.NOT_NEGATIVE
- ), false), new PermanentsOnTheBattlefieldCondition(filter),
- "When {this} dies, if you control a Vraska planeswalker, "
- + "you gain life equal to {this}'s power."
- ));
+ this.addAbility(new DiesSourceTriggeredAbility(new GainLifeEffect(SourcePermanentPowerValue.NOT_NEGATIVE)
+ .setText("you gain life equal to {this}'s power"), false).withInterveningIf(condition));
}
private AttendantOfVraska(final AttendantOfVraska card) {
diff --git a/Mage.Sets/src/mage/cards/a/AuramancersGuise.java b/Mage.Sets/src/mage/cards/a/AuramancersGuise.java
index a63e6660004..c2f037a973d 100644
--- a/Mage.Sets/src/mage/cards/a/AuramancersGuise.java
+++ b/Mage.Sets/src/mage/cards/a/AuramancersGuise.java
@@ -1,4 +1,3 @@
-
package mage.cards.a;
import mage.abilities.Ability;
@@ -18,11 +17,11 @@ import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
-import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
import java.util.UUID;
/**
- *
* @author spjspj
*/
public final class AuramancersGuise extends CardImpl {
@@ -36,16 +35,16 @@ public final class AuramancersGuise extends CardImpl {
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
- Ability ability = new EnchantAbility(auraTarget);
- this.addAbility(ability);
+ this.addAbility(new EnchantAbility(auraTarget));
// Enchanted creature gets +2/+2 for each Aura attached to it and has vigilance.
- DynamicValue ptBoost = new EnchantedCreatureAurasCount();
- BoostEnchantedEffect effect = new BoostEnchantedEffect(ptBoost, ptBoost, Duration.WhileOnBattlefield);
- effect.setText("Enchanted creature gets +2/+2 for each Aura attached to it");
- SimpleStaticAbility ability2 = new SimpleStaticAbility(effect);
- ability2.addEffect(new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA).setText("and has vigilance"));
- this.addAbility(ability2);
+ Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(
+ AuramancersGuiseValue.instance, AuramancersGuiseValue.instance, Duration.WhileOnBattlefield
+ ));
+ ability.addEffect(new GainAbilityAttachedEffect(
+ VigilanceAbility.getInstance(), AttachmentType.AURA
+ ).setText("and has vigilance"));
+ this.addAbility(ability);
}
private AuramancersGuise(final AuramancersGuise card) {
@@ -58,48 +57,40 @@ public final class AuramancersGuise extends CardImpl {
}
}
-class EnchantedCreatureAurasCount implements DynamicValue {
-
- public EnchantedCreatureAurasCount() {
- }
-
- private EnchantedCreatureAurasCount(final EnchantedCreatureAurasCount dynamicValue) {
- }
+enum AuramancersGuiseValue implements DynamicValue {
+ instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
- int count = 0;
- Permanent aura = game.getPermanent(sourceAbility.getSourceId());
- if (aura != null) {
- Permanent permanent = game.getPermanent(aura.getAttachedTo());
- if (permanent != null) {
- List attachments = permanent.getAttachments();
- for (UUID attachmentId : attachments) {
- Permanent attached = game.getPermanent(attachmentId);
- if (attached != null && attached.hasSubtype(SubType.AURA, game)) {
- count++;
- }
-
- }
- return 2 * count;
- }
- }
- return count;
+ Permanent permanent = Optional
+ .ofNullable(sourceAbility.getSourcePermanentIfItStillExists(game))
+ .map(Permanent::getAttachedTo)
+ .map(game::getPermanent)
+ .orElse(null);
+ return permanent != null
+ ? 2 * permanent
+ .getAttachments()
+ .stream()
+ .map(game::getPermanent)
+ .filter(Objects::nonNull)
+ .filter(p -> p.hasSubtype(SubType.AURA, game))
+ .mapToInt(x -> 1)
+ .sum()
+ : 0;
}
@Override
- public EnchantedCreatureAurasCount copy() {
- return new EnchantedCreatureAurasCount(this);
- }
-
- @Override
- public String toString() {
- return "1";
+ public AuramancersGuiseValue copy() {
+ return this;
}
@Override
public String getMessage() {
- return "of its auras";
+ return "for each Aura attached to it";
}
+ @Override
+ public String toString() {
+ return "2";
+ }
}
diff --git a/Mage.Sets/src/mage/cards/a/AuroraChampion.java b/Mage.Sets/src/mage/cards/a/AuroraChampion.java
index c21eefb425c..d712378e719 100644
--- a/Mage.Sets/src/mage/cards/a/AuroraChampion.java
+++ b/Mage.Sets/src/mage/cards/a/AuroraChampion.java
@@ -1,33 +1,35 @@
-
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.TapTargetEffect;
-import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.filter.FilterPermanent;
import mage.filter.common.FilterTeamPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCreaturePermanent;
+import java.util.UUID;
+
/**
- *
* @author TheElk801
*/
public final class AuroraChampion extends CardImpl {
- private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "another Warrior");
+ private static final FilterPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "your team controls another Warrior");
static {
filter.add(AnotherPredicate.instance);
}
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, false);
+
public AuroraChampion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
@@ -37,11 +39,7 @@ public final class AuroraChampion extends CardImpl {
this.toughness = new MageInt(2);
// Whenever Aurora Champion attacks, if your team controls another Warrior, tap target creature.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new TapTargetEffect(), false),
- new PermanentsOnTheBattlefieldCondition(filter),
- "Whenever {this} attacks, if your team controls another Warrior, tap target creature."
- );
+ Ability ability = new AttacksTriggeredAbility(new TapTargetEffect(), false).withInterveningIf(condition);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java b/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java
index 25c7360f97b..2ba67a29ba1 100644
--- a/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java
+++ b/Mage.Sets/src/mage/cards/a/AyarasOathsworn.java
@@ -13,6 +13,7 @@ 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.counters.CounterType;
import mage.target.common.TargetCardInLibrary;
@@ -24,8 +25,8 @@ import java.util.UUID;
*/
public final class AyarasOathsworn extends CardImpl {
- private static final Condition condition1 = new SourceHasCounterCondition(CounterType.P1P1, 0, 3);
- private static final Condition condition2 = new SourceHasCounterCondition(CounterType.P1P1, 4, 4);
+ private static final Condition condition1 = new SourceHasCounterCondition(CounterType.P1P1, ComparisonType.FEWER_THAN, 4);
+ private static final Condition condition2 = new SourceHasCounterCondition(CounterType.P1P1, ComparisonType.EQUAL_TO, 4);
public AyarasOathsworn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}");
diff --git a/Mage.Sets/src/mage/cards/a/AzorsElocutors.java b/Mage.Sets/src/mage/cards/a/AzorsElocutors.java
index d1ab1470252..633d1c6f776 100644
--- a/Mage.Sets/src/mage/cards/a/AzorsElocutors.java
+++ b/Mage.Sets/src/mage/cards/a/AzorsElocutors.java
@@ -1,28 +1,33 @@
-
package mage.cards.a;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.condition.Condition;
+import mage.abilities.condition.common.SourceHasCounterCondition;
+import mage.abilities.decorator.ConditionalOneShotEffect;
+import mage.abilities.effects.common.WinGameSourceControllerEffect;
+import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
+
+import java.util.UUID;
/**
- *
* @author LevelX2
*/
public final class AzorsElocutors extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.FILIBUSTER, 5);
+
public AzorsElocutors(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W/U}{W/U}");
this.subtype.add(SubType.HUMAN);
@@ -32,7 +37,13 @@ public final class AzorsElocutors extends CardImpl {
this.toughness = new MageInt(5);
// At the beginning of your upkeep, put a filibuster counter on Azor's Elocutors. Then if Azor's Elocutors has five or more filibuster counters on it, you win the game.
- this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AzorsElocutorsEffect()));
+ Ability ability = new BeginningOfUpkeepTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.FILIBUSTER.createInstance())
+ );
+ ability.addEffect(new ConditionalOneShotEffect(
+ new WinGameSourceControllerEffect(), condition,
+ "Then if {this} has five or more filibuster counters on it, you win the game"
+ ));
// Whenever a source deals damage to you, remove a filibuster counter from Azor's Elocutors.
this.addAbility(new AzorsElocutorsTriggeredAbility());
@@ -71,39 +82,6 @@ class AzorsElocutorsTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- return event.getTargetId().equals(this.controllerId);
- }
-}
-
-class AzorsElocutorsEffect extends OneShotEffect {
-
- AzorsElocutorsEffect() {
- super(Outcome.Benefit);
- staticText = "put a filibuster counter on Azor's Elocutors. Then if Azor's Elocutors has five or more filibuster counters on it, you win the game";
- }
-
- private AzorsElocutorsEffect(final AzorsElocutorsEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent permanent = game.getPermanent(source.getSourceId());
- if (permanent != null) {
- permanent.addCounters(CounterType.FILIBUSTER.createInstance(), source.getControllerId(), source, game);
- if (permanent.getCounters(game).getCount(CounterType.FILIBUSTER) > 4) {
- Player player = game.getPlayer(permanent.getControllerId());
- if (player != null) {
- player.won(game);
- }
- }
- return true;
- }
- return false;
- }
-
- @Override
- public AzorsElocutorsEffect copy() {
- return new AzorsElocutorsEffect(this);
+ return isControlledBy(event.getTargetId());
}
}
diff --git a/Mage.Sets/src/mage/cards/b/BakuAltar.java b/Mage.Sets/src/mage/cards/b/BakuAltar.java
index 5ef5bead80f..d74b22c6999 100644
--- a/Mage.Sets/src/mage/cards/b/BakuAltar.java
+++ b/Mage.Sets/src/mage/cards/b/BakuAltar.java
@@ -13,7 +13,6 @@ 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.filter.StaticFilters;
import mage.game.permanent.token.SpiritToken;
@@ -27,7 +26,7 @@ public final class BakuAltar extends CardImpl {
public BakuAltar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}");
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Baku Altar.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance(1)), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance(1)), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {2}, {tap}, Remove a ki counter from Baku Altar: Create a 1/1 colorless Spirit creature token.
Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SpiritToken(), 1), new GenericManaCost(2));
ability.addCost(new TapSourceCost());
diff --git a/Mage.Sets/src/mage/cards/b/BalduvianAtrocity.java b/Mage.Sets/src/mage/cards/b/BalduvianAtrocity.java
index 09b72a49a57..1661d5b4ccd 100644
--- a/Mage.Sets/src/mage/cards/b/BalduvianAtrocity.java
+++ b/Mage.Sets/src/mage/cards/b/BalduvianAtrocity.java
@@ -1,22 +1,20 @@
package mage.cards.b;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.HasteAbility;
-import mage.cards.Card;
-import mage.constants.*;
import mage.abilities.keyword.KickerAbility;
import mage.abilities.keyword.MenaceAbility;
+import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
+import mage.constants.*;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
@@ -26,8 +24,9 @@ import mage.target.common.TargetCardInYourGraveyard;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
+import java.util.UUID;
+
/**
- *
* @author weirddan455
*/
public final class BalduvianAtrocity extends CardImpl {
@@ -53,11 +52,7 @@ public final class BalduvianAtrocity extends CardImpl {
this.addAbility(new MenaceAbility(false));
// When Balduvian Atrocity enters the battlefield, if it was kicked, return target creature card with mana value 3 or less from your graveyard to the battlefield. It gains haste. Sacrifice it at the beginning of the next end step.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new BalduvianAtrocityEffect()),
- KickedCondition.ONCE,
- "When {this} enters, if it was kicked, return target creature card with mana value 3 or less from your graveyard to the battlefield. It gains haste. Sacrifice it at the beginning of the next end step."
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(new BalduvianAtrocityEffect()).withInterveningIf(KickedCondition.ONCE);
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
}
@@ -76,7 +71,8 @@ class BalduvianAtrocityEffect extends OneShotEffect {
BalduvianAtrocityEffect() {
super(Outcome.PutCreatureInPlay);
- this.staticText = "return target creature card with mana value 3 or less from your graveyard to the battlefield. It gains haste. Sacrifice it at the beginning of the next end step.";
+ this.staticText = "return target creature card with mana value 3 or less from your graveyard to the battlefield. " +
+ "It gains haste. Sacrifice it at the beginning of the next end step.";
}
private BalduvianAtrocityEffect(final BalduvianAtrocityEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java b/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java
index 8129e6229d3..a6a9df732da 100644
--- a/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java
+++ b/Mage.Sets/src/mage/cards/b/BalladOfTheBlackFlag.java
@@ -9,7 +9,7 @@ import mage.constants.CardType;
import mage.constants.SagaChapter;
import mage.constants.SubType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import java.util.UUID;
@@ -18,7 +18,10 @@ import java.util.UUID;
*/
public final class BalladOfTheBlackFlag extends CardImpl {
- private static final FilterCard filter = new FilterHistoricCard();
+ private static final FilterCard filter = new FilterCard("historic card");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
public BalladOfTheBlackFlag(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}");
diff --git a/Mage.Sets/src/mage/cards/b/BanditsTalent.java b/Mage.Sets/src/mage/cards/b/BanditsTalent.java
index f9e840fbc0c..3dce439ecf4 100644
--- a/Mage.Sets/src/mage/cards/b/BanditsTalent.java
+++ b/Mage.Sets/src/mage/cards/b/BanditsTalent.java
@@ -54,7 +54,7 @@ public final class BanditsTalent extends CardImpl {
this.addAbility(new ClassLevelAbility(2, "{B}"));
// At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, they lose 2 life.
this.addAbility(new SimpleStaticAbility(new GainClassAbilitySourceEffect(new BeginningOfUpkeepTriggeredAbility(
- TargetController.OPPONENT, new ConditionalOneShotEffect(new LoseLifeTargetEffect(2), new CardsInHandCondition(ComparisonType.OR_LESS, 1, TargetController.ACTIVE)),
+ TargetController.OPPONENT, new ConditionalOneShotEffect(new LoseLifeTargetEffect(2).setText("they lose 2 life"), new CardsInHandCondition(ComparisonType.OR_LESS, 1, TargetController.ACTIVE)),
false), 2)));
// {3}{B}: Level 3
diff --git a/Mage.Sets/src/mage/cards/b/BarrenGlory.java b/Mage.Sets/src/mage/cards/b/BarrenGlory.java
index 521770cda00..6fd39c760b5 100644
--- a/Mage.Sets/src/mage/cards/b/BarrenGlory.java
+++ b/Mage.Sets/src/mage/cards/b/BarrenGlory.java
@@ -1,42 +1,37 @@
-
package mage.cards.b;
-import java.util.UUID;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.CompoundCondition;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ComparisonType;
-import mage.filter.common.FilterControlledPermanent;
-import mage.filter.predicate.mageobject.AnotherPredicate;
+import mage.filter.StaticFilters;
+
+import java.util.UUID;
/**
* @author fireshoes
*/
public final class BarrenGlory extends CardImpl {
- private static final FilterControlledPermanent filter = new FilterControlledPermanent();
-
- static {
- filter.add(AnotherPredicate.instance);
- }
+ private static final Condition condition = new CompoundCondition(
+ "you control no permanents other than this enchantment and have no cards in hand",
+ new CardsInHandCondition(ComparisonType.EQUAL_TO, 0),
+ new PermanentsOnTheBattlefieldCondition(
+ StaticFilters.FILTER_OTHER_CONTROLLED_PERMANENTS, ComparisonType.EQUAL_TO, 0
+ )
+ );
public BarrenGlory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}{W}");
// At the beginning of your upkeep, if you control no permanents other than Barren Glory and have no cards in hand, you win the game.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()),
- new CompoundCondition(
- new CardsInHandCondition(ComparisonType.EQUAL_TO, 0),
- new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0)
- ),
- "At the beginning of your upkeep, if you control no permanents other than {this} and have no cards in hand, you win the game"));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition));
}
private BarrenGlory(final BarrenGlory card) {
diff --git a/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java b/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java
index 70da770dc14..e18e185f475 100644
--- a/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java
+++ b/Mage.Sets/src/mage/cards/b/BarrinTolarianArchmage.java
@@ -2,12 +2,11 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@@ -50,12 +49,8 @@ public final class BarrinTolarianArchmage extends CardImpl {
this.addAbility(ability);
// At the beginning of your end step, if a permanent was put into your hand from the battlefield this turn, draw a card.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfEndStepTriggeredAbility(
- new DrawCardSourceControllerEffect(1)
- ), BarrinTolarianArchmageCondition.instance, "At the beginning of your end step, " +
- "if a permanent was put into your hand from the battlefield this turn, draw a card."
- ), new BarrinTolarianArchmageWatcher());
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(1))
+ .withInterveningIf(BarrinTolarianArchmageCondition.instance), new BarrinTolarianArchmageWatcher());
}
private BarrinTolarianArchmage(final BarrinTolarianArchmage card) {
@@ -76,6 +71,11 @@ enum BarrinTolarianArchmageCondition implements Condition {
BarrinTolarianArchmageWatcher watcher = game.getState().getWatcher(BarrinTolarianArchmageWatcher.class);
return watcher != null && watcher.checkPlayer(source.getControllerId());
}
+
+ @Override
+ public String toString() {
+ return "a permanent was put into your hand from the battlefield this turn";
+ }
}
class BarrinTolarianArchmageWatcher extends Watcher {
diff --git a/Mage.Sets/src/mage/cards/b/BatWhisperer.java b/Mage.Sets/src/mage/cards/b/BatWhisperer.java
index 0f7970ace24..236c103da93 100644
--- a/Mage.Sets/src/mage/cards/b/BatWhisperer.java
+++ b/Mage.Sets/src/mage/cards/b/BatWhisperer.java
@@ -3,7 +3,6 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.OpponentsLostLifeCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.hint.common.OpponentsLostLifeHint;
import mage.cards.CardImpl;
@@ -27,11 +26,8 @@ public final class BatWhisperer extends CardImpl {
this.toughness = new MageInt(2);
// When Bat Whisperer enters the battlefield, if an opponent lost life this turn, create a 1/1 black Bat creature token with flying.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BatToken())),
- OpponentsLostLifeCondition.instance, "When {this} enters, " +
- "if an opponent lost life this turn, create a 1/1 black Bat creature token with flying."
- ).addHint(OpponentsLostLifeHint.instance));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BatToken()))
+ .withInterveningIf(OpponentsLostLifeCondition.instance).addHint(OpponentsLostLifeHint.instance));
}
private BatWhisperer(final BatWhisperer card) {
diff --git a/Mage.Sets/src/mage/cards/b/BatteryBearer.java b/Mage.Sets/src/mage/cards/b/BatteryBearer.java
index 52363581bf5..96f2d2d5f96 100644
--- a/Mage.Sets/src/mage/cards/b/BatteryBearer.java
+++ b/Mage.Sets/src/mage/cards/b/BatteryBearer.java
@@ -14,7 +14,6 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterArtifactSpell;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.permanent.token.PowerstoneToken;
@@ -26,9 +25,10 @@ import java.util.UUID;
public final class BatteryBearer extends CardImpl {
private static final FilterSpell filter
- = new FilterArtifactSpell("an artifact spell with mana value 6 or greater");
+ = new FilterSpell("an artifact spell with mana value 6 or greater");
static {
+ filter.add(CardType.ARTIFACT.getPredicate());
filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 5));
}
diff --git a/Mage.Sets/src/mage/cards/b/BattleOfWits.java b/Mage.Sets/src/mage/cards/b/BattleOfWits.java
index 054889aad3d..3603fad84ff 100644
--- a/Mage.Sets/src/mage/cards/b/BattleOfWits.java
+++ b/Mage.Sets/src/mage/cards/b/BattleOfWits.java
@@ -1,32 +1,31 @@
-
package mage.cards.b;
-import java.util.UUID;
import mage.abilities.Ability;
-import mage.abilities.TriggeredAbility;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.game.Controllable;
import mage.game.Game;
+import mage.players.Library;
import mage.players.Player;
+import java.util.Optional;
+import java.util.UUID;
+
/**
- *
* @author North
*/
public final class BattleOfWits extends CardImpl {
public BattleOfWits(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}");
-
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}");
// At the beginning of your upkeep, if you have 200 or more cards in your library, you win the game.
- TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect());
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new BattleOfWitsCondition(), "At the beginning of your upkeep, if you have 200 or more cards in your library, you win the game."));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect())
+ .withInterveningIf(BattleOfWitsCondition.instance));
}
private BattleOfWits(final BattleOfWits card) {
@@ -39,14 +38,22 @@ public final class BattleOfWits extends CardImpl {
}
}
-class BattleOfWitsCondition implements Condition {
+enum BattleOfWitsCondition implements Condition {
+ instance;
@Override
public boolean apply(Game game, Ability source) {
- Player player = game.getPlayer(source.getControllerId());
- if (player != null && player.getLibrary().size() >= 200) {
- return true;
- }
- return false;
+ return Optional
+ .ofNullable(source)
+ .map(Controllable::getControllerId)
+ .map(game::getPlayer)
+ .map(Player::getLibrary)
+ .map(Library::size)
+ .orElse(0) >= 200;
+ }
+
+ @Override
+ public String toString() {
+ return "you have 200 or more cards in your library";
}
}
diff --git a/Mage.Sets/src/mage/cards/b/BattlewingMystic.java b/Mage.Sets/src/mage/cards/b/BattlewingMystic.java
index 27ee0950304..a9321405dca 100644
--- a/Mage.Sets/src/mage/cards/b/BattlewingMystic.java
+++ b/Mage.Sets/src/mage/cards/b/BattlewingMystic.java
@@ -1,21 +1,21 @@
package mage.cards.b;
-import java.util.UUID;
import mage.MageInt;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
-import mage.constants.SubType;
-import mage.abilities.keyword.KickerAbility;
import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.keyword.KickerAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.SubType;
+
+import java.util.UUID;
/**
- *
* @author weirddan455
*/
public final class BattlewingMystic extends CardImpl {
@@ -35,12 +35,9 @@ public final class BattlewingMystic extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Battlewing Mystic enters the battlefield, if it was kicked, discard your hand, then draw two cards.
- EntersBattlefieldTriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect());
- triggeredAbility.addEffect(new DrawCardSourceControllerEffect(2));
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- triggeredAbility, KickedCondition.ONCE,
- "When {this} enters, if it was kicked, discard your hand, then draw two cards."
- ));
+ Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardHandControllerEffect()).withInterveningIf(KickedCondition.ONCE);
+ ability.addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then"));
+ this.addAbility(ability);
}
private BattlewingMystic(final BattlewingMystic card) {
diff --git a/Mage.Sets/src/mage/cards/b/BelligerentOfTheBall.java b/Mage.Sets/src/mage/cards/b/BelligerentOfTheBall.java
index 9fa2fe334d1..a1ceab481a7 100644
--- a/Mage.Sets/src/mage/cards/b/BelligerentOfTheBall.java
+++ b/Mage.Sets/src/mage/cards/b/BelligerentOfTheBall.java
@@ -2,12 +2,11 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.condition.common.CelebrationCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.MenaceAbility;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
@@ -32,16 +31,10 @@ public final class BelligerentOfTheBall extends CardImpl {
this.toughness = new MageInt(3);
// Celebration -- At the beginning of combat on your turn, if two or more nonland permanents entered the battlefield under your control this turn, target creature you control gets +1/+0 and gains menace until end of turn.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- new BoostTargetEffect(1, 0)
- ),
- CelebrationCondition.instance, "At the beginning of combat on your turn, if two or more nonland "
- + "permanents entered the battlefield under your control this turn, target creature you control "
- + "gets +1/+0 and gains menace until end of turn."
- + " (It can't be blocked except by two or more creatures.)"
- );
- ability.addEffect(new GainAbilityTargetEffect(new MenaceAbility(false)));
+ Ability ability = new BeginningOfCombatTriggeredAbility(new BoostTargetEffect(1, 0)
+ .setText("target creature you control gets +1/+0")).withInterveningIf(CelebrationCondition.instance);
+ ability.addEffect(new GainAbilityTargetEffect(new MenaceAbility(false))
+ .setText("and gains menace until end of turn"));
ability.addTarget(new TargetControlledCreaturePermanent());
ability.setAbilityWord(AbilityWord.CELEBRATION);
ability.addHint(CelebrationCondition.getHint());
diff --git a/Mage.Sets/src/mage/cards/b/BenalishEmissary.java b/Mage.Sets/src/mage/cards/b/BenalishEmissary.java
index df1bc77cfd0..84854b58014 100644
--- a/Mage.Sets/src/mage/cards/b/BenalishEmissary.java
+++ b/Mage.Sets/src/mage/cards/b/BenalishEmissary.java
@@ -1,12 +1,9 @@
-
package mage.cards.b;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.keyword.KickerAbility;
import mage.cards.CardImpl;
@@ -15,26 +12,26 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.target.common.TargetLandPermanent;
-/**
- *
- * @author LoneFox
+import java.util.UUID;
+/**
+ * @author LoneFox
*/
public final class BenalishEmissary extends CardImpl {
public BenalishEmissary(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.subtype.add(SubType.HUMAN, SubType.WIZARD);
this.power = new MageInt(1);
this.toughness = new MageInt(4);
// Kicker {1}{G}
this.addAbility(new KickerAbility("{1}{G}"));
+
// When Benalish Emissary enters the battlefield, if it was kicked, destroy target land.
- TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect());
+ Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()).withInterveningIf(KickedCondition.ONCE);
ability.addTarget(new TargetLandPermanent());
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.ONCE,
- "When {this} enters, if it was kicked, destroy target land."));
+ this.addAbility(ability);
}
private BenalishEmissary(final BenalishEmissary card) {
diff --git a/Mage.Sets/src/mage/cards/b/BenalishSleeper.java b/Mage.Sets/src/mage/cards/b/BenalishSleeper.java
index 4a361f0ad34..84ac34e6243 100644
--- a/Mage.Sets/src/mage/cards/b/BenalishSleeper.java
+++ b/Mage.Sets/src/mage/cards/b/BenalishSleeper.java
@@ -3,7 +3,6 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.SacrificeAllEffect;
import mage.abilities.keyword.KickerAbility;
import mage.cards.CardImpl;
@@ -32,10 +31,7 @@ public final class BenalishSleeper extends CardImpl {
this.addAbility(new KickerAbility("{B}"));
// When Benalish Sleeper enters the battlefield, if it was kicked, each player sacrifices a creature.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(
- new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE)
- ), KickedCondition.ONCE, "When {this} enters, " +
- "if it was kicked, each player sacrifices a creature."));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE)).withInterveningIf(KickedCondition.ONCE));
}
private BenalishSleeper(final BenalishSleeper card) {
diff --git a/Mage.Sets/src/mage/cards/b/BespokeBattlegarb.java b/Mage.Sets/src/mage/cards/b/BespokeBattlegarb.java
index bad7c7acc0a..72ca2444fe4 100644
--- a/Mage.Sets/src/mage/cards/b/BespokeBattlegarb.java
+++ b/Mage.Sets/src/mage/cards/b/BespokeBattlegarb.java
@@ -1,17 +1,19 @@
package mage.cards.b;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CelebrationCondition;
import mage.abilities.costs.mana.GenericManaCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.keyword.EquipAbility;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.AbilityWord;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.constants.SubType;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.watchers.common.PermanentsEnteredBattlefieldWatcher;
@@ -28,19 +30,12 @@ public final class BespokeBattlegarb extends CardImpl {
this.subtype.add(SubType.EQUIPMENT);
// Equipped creature gets +2/+0.
- this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0, Duration.WhileOnBattlefield)));
+ this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 0)));
// Celebration -- At the beginning of combat on your turn, if two or more nonland permanents entered the battlefield under your control this turn, attach Bespoke Battlegarb to up to one target creature you control.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- new AttachEffect(
- Outcome.BoostCreature,
- "attach {this} to up to one target creature you control"
- )
- ), CelebrationCondition.instance, "At the beginning of combat on your turn, if two "
- + "or more nonland permanents entered the battlefield under your control this turn, "
- + "attach {this} to up to one target creature you control"
- );
+ Ability ability = new BeginningOfCombatTriggeredAbility(new AttachEffect(
+ Outcome.BoostCreature, "attach {this} to up to one target creature you control"
+ )).withInterveningIf(CelebrationCondition.instance);
ability.addTarget(new TargetControlledCreaturePermanent(0, 1));
ability.setAbilityWord(AbilityWord.CELEBRATION);
ability.addHint(CelebrationCondition.getHint());
diff --git a/Mage.Sets/src/mage/cards/b/BezaTheBoundingSpring.java b/Mage.Sets/src/mage/cards/b/BezaTheBoundingSpring.java
index cdf57adce26..d515076bf2e 100644
--- a/Mage.Sets/src/mage/cards/b/BezaTheBoundingSpring.java
+++ b/Mage.Sets/src/mage/cards/b/BezaTheBoundingSpring.java
@@ -10,17 +10,22 @@ import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.GainLifeEffect;
+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.StaticFilters;
+import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.token.FishNoAbilityToken;
import mage.game.permanent.token.TreasureToken;
import mage.players.Player;
+import java.util.Optional;
+import java.util.Set;
import java.util.UUID;
/**
@@ -28,6 +33,13 @@ import java.util.UUID;
*/
public final class BezaTheBoundingSpring extends CardImpl {
+ private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS);
+ private static final Condition condition2 = new OpponentControlsMoreCondition(StaticFilters.FILTER_PERMANENT_CREATURES);
+ private static final Hint hint = new ConditionHint(condition);
+ private static final Hint hint2 = new ConditionHint(condition2);
+ private static final Hint hint3 = new ConditionHint(OpponentHasMoreLifeCondition.instance);
+ private static final Hint hint4 = new ConditionHint(BezaOpponentHasMoreCardsInHandThanYouCondition.instance);
+
public BezaTheBoundingSpring(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}");
@@ -39,14 +51,23 @@ public final class BezaTheBoundingSpring extends CardImpl {
// When Beza, the Bounding Spring enters, create a Treasure token if an opponent controls more lands than you. You gain 4 life if an opponent has more life than you. Create two 1/1 blue Fish creature tokens if an opponent controls more creatures than you. Draw a card if an opponent has more cards in hand than you.
Ability ability = new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(
- new CreateTokenEffect(new TreasureToken()), new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS)));
+ new CreateTokenEffect(new TreasureToken()), condition,
+ "create a Treasure token if an opponent controls more lands than you"
+ ));
ability.addEffect(new ConditionalOneShotEffect(
- new GainLifeEffect(4), OpponentHasMoreLifeCondition.instance));
+ new GainLifeEffect(4), OpponentHasMoreLifeCondition.instance,
+ "you gain 4 life if an opponent has more life than you"
+ ));
ability.addEffect(new ConditionalOneShotEffect(
- new CreateTokenEffect(new FishNoAbilityToken(), 2), new OpponentControlsMoreCondition(StaticFilters.FILTER_PERMANENT_CREATURES)));
+ new CreateTokenEffect(new FishNoAbilityToken(), 2), condition2,
+ "Create two 1/1 blue Fish creature tokens if an opponent controls more creatures than you"
+ ));
ability.addEffect(new ConditionalOneShotEffect(
- new DrawCardSourceControllerEffect(1), BezaOpponentHasMoreCardsInHandThanYouCondition.instance));
- this.addAbility(ability);
+ new DrawCardSourceControllerEffect(1),
+ BezaOpponentHasMoreCardsInHandThanYouCondition.instance,
+ "draw a card if an opponent has more cards in hand than you"
+ ));
+ this.addAbility(ability.addHint(hint).addHint(hint2).addHint(hint3).addHint(hint4));
}
private BezaTheBoundingSpring(final BezaTheBoundingSpring card) {
@@ -61,22 +82,23 @@ public final class BezaTheBoundingSpring extends CardImpl {
//Based on MoreCardsInHandThanOpponentsCondition
enum BezaOpponentHasMoreCardsInHandThanYouCondition implements Condition {
-
instance;
@Override
public boolean apply(Game game, Ability source) {
- Player player = game.getPlayer(source.getControllerId());
- if (player != null) {
- int cardsInHand = player.getHand().size();
- for (UUID playerId : game.getOpponents(source.getControllerId())) {
- Player opponent = game.getPlayer(playerId);
- if (opponent != null && opponent.getHand().size() > cardsInHand) {
- return true;
- }
- }
- }
- return false;
+ int cardsInHand = Optional
+ .ofNullable(source)
+ .map(Controllable::getControllerId)
+ .map(game::getPlayer)
+ .map(Player::getHand)
+ .map(Set::size)
+ .orElse(0);
+ return game.getOpponents(source.getControllerId())
+ .stream()
+ .map(game::getPlayer)
+ .map(Player::getHand)
+ .mapToInt(Set::size)
+ .anyMatch(x -> x > cardsInHand);
}
@Override
diff --git a/Mage.Sets/src/mage/cards/b/BiowasteBlob.java b/Mage.Sets/src/mage/cards/b/BiowasteBlob.java
index 27285952858..f6bd6943055 100644
--- a/Mage.Sets/src/mage/cards/b/BiowasteBlob.java
+++ b/Mage.Sets/src/mage/cards/b/BiowasteBlob.java
@@ -1,12 +1,11 @@
package mage.cards.b;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.ControlACommanderCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.CreateTokenCopySourceEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -36,12 +35,8 @@ public final class BiowasteBlob extends CardImpl {
)));
// At the beginning of your upkeep, if you control a commander, create a token that's a copy of Biowaste Blob.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(
- new CreateTokenCopySourceEffect(), false
- ), ControlACommanderCondition.instance, "At the beginning of your upkeep, " +
- "if you control a commander, create a token that's a copy of {this}."
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenCopySourceEffect())
+ .withInterveningIf(ControlACommanderCondition.instance));
}
private BiowasteBlob(final BiowasteBlob card) {
diff --git a/Mage.Sets/src/mage/cards/b/BladeOfSharedSouls.java b/Mage.Sets/src/mage/cards/b/BladeOfSharedSouls.java
index 1331a8007bd..e4074b2f5a1 100644
--- a/Mage.Sets/src/mage/cards/b/BladeOfSharedSouls.java
+++ b/Mage.Sets/src/mage/cards/b/BladeOfSharedSouls.java
@@ -20,6 +20,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
+import mage.util.CardUtil;
import java.util.UUID;
@@ -67,14 +68,11 @@ enum BladeOfSharedSoulsPredicate implements ObjectSourcePlayerPredicate input, Game game) {
- return input.getSource()
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("attachedPermanent"))
- .filter(Permanent.class::isInstance)
- .map(Permanent.class::cast)
- .noneMatch(permanent -> input.getObject().getId().equals(permanent.getId())
- && input.getObject().getZoneChangeCounter(game) == permanent.getZoneChangeCounter(game));
+ return !CardUtil
+ .getEffectValueFromAbility(input.getSource(), "attachedPermanent", Permanent.class)
+ .filter(permanent -> input.getObject().getId().equals(permanent.getId())
+ && input.getObject().getZoneChangeCounter(game) == permanent.getZoneChangeCounter(game))
+ .isPresent();
}
}
@@ -141,4 +139,4 @@ class BladeOfSharedSoulsCopyEffect extends CopyEffect {
}
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java
index 1eca1c8df02..d5575de58a8 100644
--- a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java
+++ b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java
@@ -1,10 +1,9 @@
package mage.cards.b;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.MetalcraftCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.hint.common.MetalcraftHint;
@@ -23,8 +22,6 @@ import java.util.UUID;
*/
public final class BladeTribeBerserkers extends CardImpl {
- private static final String effectText = "When {this} enters, if you control three or more artifacts, {this} gets +3/+3 and gains haste until end of turn.";
-
public BladeTribeBerserkers(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
this.subtype.add(SubType.HUMAN, SubType.BERSERKER);
@@ -33,12 +30,14 @@ public final class BladeTribeBerserkers extends CardImpl {
this.toughness = new MageInt(3);
//Metalcraft — When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn.
- TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn), false);
- ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MetalcraftCondition.instance, effectText)
- .setAbilityWord(AbilityWord.METALCRAFT)
- .addHint(MetalcraftHint.instance)
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(
+ new BoostSourceEffect(3, 3, Duration.EndOfTurn)
+ .setText("{this} gets +3/+3"), false
+ ).withInterveningIf(MetalcraftCondition.instance);
+ ability.addEffect(new GainAbilitySourceEffect(
+ HasteAbility.getInstance(), Duration.EndOfTurn
+ ).setText("and gains haste until end of turn"));
+ this.addAbility(ability.setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance));
}
private BladeTribeBerserkers(final BladeTribeBerserkers card) {
diff --git a/Mage.Sets/src/mage/cards/b/BlademaneBaku.java b/Mage.Sets/src/mage/cards/b/BlademaneBaku.java
index 3538121037b..f0c57416e82 100644
--- a/Mage.Sets/src/mage/cards/b/BlademaneBaku.java
+++ b/Mage.Sets/src/mage/cards/b/BlademaneBaku.java
@@ -37,7 +37,7 @@ public final class BlademaneBaku extends CardImpl {
this.toughness = new MageInt(1);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Blademane Baku.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {1}, Remove X ki counters from Blademane Baku: For each counter removed, Blademane Baku gets +2/+0 until end of turn.
Effect effect = new BoostSourceEffect(xValue, StaticValue.get(0), Duration.EndOfTurn);
diff --git a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java
index 1a372c9bc7f..3bd656b42cd 100644
--- a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java
+++ b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java
@@ -1,10 +1,9 @@
package mage.cards.b;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.MetalcraftCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.hint.common.MetalcraftHint;
@@ -13,7 +12,6 @@ import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.target.Target;
import mage.target.TargetPlayer;
import java.util.UUID;
@@ -23,8 +21,6 @@ import java.util.UUID;
*/
public final class BleakCovenVampires extends CardImpl {
- private static final String effectText = "When {this} enters, if you control three or more artifacts, target player loses 4 life and you gain 4 life.";
-
public BleakCovenVampires(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.VAMPIRE, SubType.WARRIOR);
@@ -33,15 +29,11 @@ public final class BleakCovenVampires extends CardImpl {
this.toughness = new MageInt(3);
//Metalcraft — When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life.
- TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(4), false);
- ability.addEffect(new GainLifeEffect(4));
- Target target = new TargetPlayer();
- ability.addTarget(target);
-
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MetalcraftCondition.instance, effectText)
- .setAbilityWord(AbilityWord.METALCRAFT)
- .addHint(MetalcraftHint.instance)
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(4))
+ .withInterveningIf(MetalcraftCondition.instance);
+ ability.addEffect(new GainLifeEffect(4).concatBy("and"));
+ ability.addTarget(new TargetPlayer());
+ this.addAbility(ability.setAbilityWord(AbilityWord.METALCRAFT).addHint(MetalcraftHint.instance));
}
private BleakCovenVampires(final BleakCovenVampires card) {
diff --git a/Mage.Sets/src/mage/cards/b/BlindObedience.java b/Mage.Sets/src/mage/cards/b/BlindObedience.java
index 5f0a7323da0..a8c942dd0ad 100644
--- a/Mage.Sets/src/mage/cards/b/BlindObedience.java
+++ b/Mage.Sets/src/mage/cards/b/BlindObedience.java
@@ -24,7 +24,7 @@ public final class BlindObedience extends CardImpl {
// Artifacts and creatures your opponents control enter the battlefield tapped.
this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(
StaticFilters.FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE
- ).setText("artifacts and creatures your opponents control enter the battlefield tapped")));
+ ).setText("artifacts and creatures your opponents control enter tapped")));
}
diff --git a/Mage.Sets/src/mage/cards/b/BlindZealot.java b/Mage.Sets/src/mage/cards/b/BlindZealot.java
index 2d1cb8f963b..502ab8e6f1b 100644
--- a/Mage.Sets/src/mage/cards/b/BlindZealot.java
+++ b/Mage.Sets/src/mage/cards/b/BlindZealot.java
@@ -14,7 +14,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -39,7 +39,7 @@ public final class BlindZealot extends CardImpl {
OneShotEffect effect = new DoIfCostPaid(new DestroyTargetEffect(), new SacrificeSourceCost());
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java
index a8beebc7b75..b412fd2f57f 100644
--- a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java
+++ b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java
@@ -5,7 +5,6 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
@@ -26,7 +25,7 @@ import java.util.UUID;
public final class BlizzardStrix extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("another target permanent");
- private static final FilterPermanent filter2 = new FilterPermanent();
+ private static final FilterPermanent filter2 = new FilterPermanent("you control another snow permanent");
static {
filter.add(AnotherPredicate.instance);
@@ -51,12 +50,9 @@ public final class BlizzardStrix extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Blizzard Strix enters the battlefield, if you control another snow permanent, exile target permanent other than Blizzard Strix. Return that card to the battlefield under its owner's control at the beginning of the next end step.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect()), condition,
- "When {this} enters, if you control another snow permanent, " +
- "exile target permanent other than {this}. Return that card to the battlefield " +
- "under its owner's control at the beginning of the next end step."
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(new ExileReturnBattlefieldNextEndStepTargetEffect()
+ .setText("exile target permanent other than {this}. Return that card to the " +
+ "battlefield under its owner's control at the beginning of the next end step"));
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java b/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java
index 660376d076c..a93045dbc35 100644
--- a/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java
+++ b/Mage.Sets/src/mage/cards/b/BloodchiefAscension.java
@@ -1,16 +1,14 @@
-
package mage.cards.b;
-import java.util.UUID;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.OpponentLostLifeCondition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -18,14 +16,17 @@ import mage.constants.ComparisonType;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.counters.CounterType;
-import mage.filter.FilterCard;
+import mage.filter.StaticFilters;
+
+import java.util.UUID;
/**
- *
* @author LevelX2
*/
public final class BloodchiefAscension extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 3);
+
public BloodchiefAscension(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}");
@@ -36,14 +37,12 @@ public final class BloodchiefAscension extends CardImpl {
));
// Whenever a card is put into an opponent's graveyard from anywhere, if Bloodchief Ascension has three or more quest counters on it, you may have that player lose 2 life. If you do, you gain 2 life.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
- new LoseLifeTargetEffect(2), true, new FilterCard("a card"), TargetController.OPPONENT, SetTargetPointer.PLAYER),
- new SourceHasCounterCondition(CounterType.QUEST, 3, Integer.MAX_VALUE),
- "Whenever a card is put into an opponent's graveyard from anywhere, if {this} has three or more quest counters on it, you may have that player lose 2 life. If you do, you gain 2 life");
- ability.addEffect(new GainLifeEffect(2));
+ Ability ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility(
+ new LoseLifeTargetEffect(2), true, StaticFilters.FILTER_CARD_A,
+ TargetController.OPPONENT, SetTargetPointer.PLAYER
+ ).withInterveningIf(condition);
+ ability.addEffect(new GainLifeEffect(2).concatBy("If you do,"));
this.addAbility(ability);
-
}
private BloodchiefAscension(final BloodchiefAscension card) {
diff --git a/Mage.Sets/src/mage/cards/b/BloodhallPriest.java b/Mage.Sets/src/mage/cards/b/BloodhallPriest.java
index 9a7f4509167..343a50d980d 100644
--- a/Mage.Sets/src/mage/cards/b/BloodhallPriest.java
+++ b/Mage.Sets/src/mage/cards/b/BloodhallPriest.java
@@ -1,13 +1,10 @@
-
package mage.cards.b;
-import java.util.UUID;
import mage.MageInt;
-import mage.abilities.TriggeredAbility;
+import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.condition.common.HellbentCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.keyword.MadnessAbility;
import mage.cards.CardImpl;
@@ -16,8 +13,9 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.target.common.TargetAnyTarget;
+import java.util.UUID;
+
/**
- *
* @author fireshoes
*/
public final class BloodhallPriest extends CardImpl {
@@ -29,13 +27,10 @@ public final class BloodhallPriest extends CardImpl {
this.toughness = new MageInt(4);
// Whenever Bloodhall Priest enters the battlefield or attacks, if you have no cards in hand, Bloodhall Priest deals 2 damage to any target.
- TriggeredAbility triggeredAbility = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DamageTargetEffect(2));
- triggeredAbility.addTarget(new TargetAnyTarget());
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- triggeredAbility,
- HellbentCondition.instance,
- "Whenever {this} enters or attacks, if you have no cards in hand, {this} deals 2 damage to any target"
- ));
+ Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DamageTargetEffect(2))
+ .withInterveningIf(HellbentCondition.instance);
+ ability.addTarget(new TargetAnyTarget());
+ this.addAbility(ability);
// Madness {1}{B}{R}
this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{B}{R}")));
diff --git a/Mage.Sets/src/mage/cards/b/BloodtitheCollector.java b/Mage.Sets/src/mage/cards/b/BloodtitheCollector.java
index 5845f5f9b7a..587d9757c0a 100644
--- a/Mage.Sets/src/mage/cards/b/BloodtitheCollector.java
+++ b/Mage.Sets/src/mage/cards/b/BloodtitheCollector.java
@@ -3,7 +3,6 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.OpponentsLostLifeCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.discard.DiscardEachPlayerEffect;
import mage.abilities.hint.common.OpponentsLostLifeHint;
import mage.abilities.keyword.FlyingAbility;
@@ -32,11 +31,8 @@ public final class BloodtitheCollector extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When this creature enters, if an opponent lost life this turn, each opponent discards a card.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT)),
- OpponentsLostLifeCondition.instance, "When this creature enters, " +
- "if an opponent lost life this turn, each opponent discards a card."
- ).addHint(OpponentsLostLifeHint.instance));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT))
+ .withInterveningIf(OpponentsLostLifeCondition.instance).addHint(OpponentsLostLifeHint.instance));
}
private BloodtitheCollector(final BloodtitheCollector card) {
diff --git a/Mage.Sets/src/mage/cards/b/BlotOut.java b/Mage.Sets/src/mage/cards/b/BlotOut.java
index 65abb8e9870..cff566f0886 100644
--- a/Mage.Sets/src/mage/cards/b/BlotOut.java
+++ b/Mage.Sets/src/mage/cards/b/BlotOut.java
@@ -10,9 +10,10 @@ import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterControlledCreatureOrPlaneswalkerPermanent;
+import mage.filter.common.FilterControlledPermanent;
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;
@@ -67,11 +68,15 @@ class BlotOutEffect extends OneShotEffect {
}
}
- private static final FilterPermanent filter = new FilterControlledCreatureOrPlaneswalkerPermanent(
+ private static final FilterPermanent filter = new FilterControlledPermanent(
"creature or planeswalker you control with the greatest mana value"
);
static {
+ filter.add(Predicates.or(
+ CardType.CREATURE.getPredicate(),
+ CardType.PLANESWALKER.getPredicate()
+ ));
filter.add(BlotOutPredicate.instance);
}
diff --git a/Mage.Sets/src/mage/cards/b/BlowflyInfestation.java b/Mage.Sets/src/mage/cards/b/BlowflyInfestation.java
index b95a9a435ce..d0e0f7afcd7 100644
--- a/Mage.Sets/src/mage/cards/b/BlowflyInfestation.java
+++ b/Mage.Sets/src/mage/cards/b/BlowflyInfestation.java
@@ -1,45 +1,38 @@
package mage.cards.b;
-import java.util.UUID;
import mage.abilities.Ability;
-import mage.abilities.TriggeredAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
-import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
-import mage.abilities.effects.Effect;
-import mage.abilities.effects.OneShotEffect;
+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.game.Game;
-import mage.game.permanent.Permanent;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
+import java.util.UUID;
+
/**
- *
- *
- *
* @author jeffwadsworth
- *
- *
- *
*/
public final class BlowflyInfestation extends CardImpl {
- private static final String rule = "Whenever a creature dies, if it had a -1/-1 counter on it, put a -1/-1 counter on target creature.";
+ private static final FilterPermanent filter = new FilterCreaturePermanent();
+
+ static {
+ filter.add(CounterType.M1M1.getPredicate());
+ }
public BlowflyInfestation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
- //Whenever a creature dies, if it had a -1/-1 counter on it, put a -1/-1 counter on target creature.
- Effect effect = new BlowflyInfestationEffect();
- TriggeredAbility triggeredAbility = new DiesCreatureTriggeredAbility(effect, false, false, true);
- triggeredAbility.addTarget(new TargetCreaturePermanent());
- Condition condition = new BlowflyInfestationCondition();
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggeredAbility, condition, rule));
-
+ // Whenever a creature dies, if it had a -1/-1 counter on it, put a -1/-1 counter on target creature.
+ Ability ability = new DiesCreatureTriggeredAbility(
+ new AddCountersTargetEffect(CounterType.M1M1.createInstance()), false, filter
+ ).setTriggerPhrase("Whenever a creature dies, if it had a -1/-1 counter on it, ");
+ ability.addTarget(new TargetCreaturePermanent());
+ this.addAbility(ability);
}
private BlowflyInfestation(final BlowflyInfestation card) {
@@ -51,47 +44,3 @@ public final class BlowflyInfestation extends CardImpl {
return new BlowflyInfestation(this);
}
}
-
-class BlowflyInfestationCondition implements Condition {
-
- private Permanent permanent;
-
- @Override
- public boolean apply(Game game, Ability source) {
- for (Effect effect : source.getEffects()) {
- if (effect.getTargetPointer().getFirst(game, source) != null) {
- permanent = effect.getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
- }
- }
- if (permanent != null) {
- return permanent.getCounters(game).containsKey(CounterType.M1M1);
- }
- return false;
- }
-}
-
-class BlowflyInfestationEffect extends OneShotEffect {
-
- BlowflyInfestationEffect() {
- super(Outcome.Detriment);
- }
-
- private BlowflyInfestationEffect(final BlowflyInfestationEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent creature = game.getPermanent(source.getFirstTarget());
- if (creature != null) {
- creature.addCounters(CounterType.M1M1.createInstance(), source.getControllerId(), source, game);
- return true;
- }
- return false;
- }
-
- @Override
- public BlowflyInfestationEffect copy() {
- return new BlowflyInfestationEffect(this);
- }
-}
diff --git a/Mage.Sets/src/mage/cards/b/BogBadger.java b/Mage.Sets/src/mage/cards/b/BogBadger.java
index 95556d1325b..a9e42cba42d 100644
--- a/Mage.Sets/src/mage/cards/b/BogBadger.java
+++ b/Mage.Sets/src/mage/cards/b/BogBadger.java
@@ -3,7 +3,6 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.KickedCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.KickerAbility;
import mage.abilities.keyword.MenaceAbility;
@@ -32,13 +31,9 @@ public final class BogBadger extends CardImpl {
this.addAbility(new KickerAbility("{B}"));
// When Bog Badger enters the battlefield, if it was kicked, creatures you control gain menace until end of turn.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
- new MenaceAbility(false), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES
- )), KickedCondition.ONCE, "When {this} enters, " +
- "if it was kicked, creatures you control gain menace until end of turn. " +
- "(A creature with menace can't be blocked except by two or more creatures.)"
- ));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
+ new MenaceAbility(false), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES
+ )).withInterveningIf(KickedCondition.ONCE));
}
private BogBadger(final BogBadger card) {
diff --git a/Mage.Sets/src/mage/cards/b/BorealOutrider.java b/Mage.Sets/src/mage/cards/b/BorealOutrider.java
index c66c0c8c7b0..94b9fd62674 100644
--- a/Mage.Sets/src/mage/cards/b/BorealOutrider.java
+++ b/Mage.Sets/src/mage/cards/b/BorealOutrider.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@@ -35,14 +34,10 @@ public final class BorealOutrider extends CardImpl {
this.toughness = new MageInt(2);
// Whenever you cast a creature spell, if {S} of any of that spell's color was spent to cast it, that creature enters the battlefield with an additional +1/+1 counter on it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new SpellCastControllerTriggeredAbility(
- new BorealOutriderEffect(), StaticFilters.FILTER_SPELL_A_CREATURE,
- false, SetTargetPointer.SPELL
- ), BorealOutriderCondition.instance, "Whenever you cast a creature spell, " +
- "if {S} of any of that spell's colors was spent to cast it, that creature " +
- "enters the battlefield with an additional +1/+1 counter on it."
- ));
+ this.addAbility(new SpellCastControllerTriggeredAbility(
+ new BorealOutriderEffect(), StaticFilters.FILTER_SPELL_A_CREATURE,
+ false, SetTargetPointer.SPELL
+ ).withInterveningIf(BorealOutriderCondition.instance));
}
private BorealOutrider(final BorealOutrider card) {
@@ -63,6 +58,11 @@ enum BorealOutriderCondition implements Condition {
Spell spell = (Spell) source.getEffects().get(0).getValue("spellCast");
return spell != null && ManaPaidSourceWatcher.checkSnowColor(spell, game);
}
+
+ @Override
+ public String toString() {
+ return "{S} of any of that spell's color was spent to cast it";
+ }
}
class BorealOutriderEffect extends ReplacementEffectImpl {
diff --git a/Mage.Sets/src/mage/cards/b/BorosStrikeCaptain.java b/Mage.Sets/src/mage/cards/b/BorosStrikeCaptain.java
new file mode 100644
index 00000000000..f753b05abf7
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/b/BorosStrikeCaptain.java
@@ -0,0 +1,142 @@
+package mage.cards.b;
+
+import mage.MageInt;
+import mage.MageObjectReference;
+import mage.abilities.Ability;
+import mage.abilities.condition.Condition;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.hint.ConditionHint;
+import mage.abilities.hint.Hint;
+import mage.abilities.keyword.BattalionAbility;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.players.Player;
+import mage.util.CardUtil;
+import mage.watchers.Watcher;
+
+import java.util.*;
+
+/**
+ * @author TheElk801
+ */
+public final class BorosStrikeCaptain extends CardImpl {
+
+ public BorosStrikeCaptain(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R/W}{R/W}");
+
+ this.subtype.add(SubType.MINOTAUR);
+ this.subtype.add(SubType.SOLDIER);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(3);
+
+ // Battalion -- Whenever Boros Strike-Captain and at least two other creatures attack, exile the top card of your library. During any turn you attacked with three or more creatures, you may play that card.
+ this.addAbility(new BattalionAbility(new BorosStrikeCaptainEffect())
+ .addHint(BorosStrikeCaptainCondition.getHint()), new BorosStrikeCaptainWatcher());
+ }
+
+ private BorosStrikeCaptain(final BorosStrikeCaptain card) {
+ super(card);
+ }
+
+ @Override
+ public BorosStrikeCaptain copy() {
+ return new BorosStrikeCaptain(this);
+ }
+}
+
+class BorosStrikeCaptainEffect extends OneShotEffect {
+
+ BorosStrikeCaptainEffect() {
+ super(Outcome.Benefit);
+ staticText = "exile the top card of your library. During any turn you attacked " +
+ "with three or more creatures, you may play that card";
+ }
+
+ private BorosStrikeCaptainEffect(final BorosStrikeCaptainEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public BorosStrikeCaptainEffect copy() {
+ return new BorosStrikeCaptainEffect(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.moveCards(card, Zone.EXILED, source, game);
+ CardUtil.makeCardPlayable(
+ game, source, card, false, Duration.Custom, false,
+ player.getId(), BorosStrikeCaptainCondition.instance
+ );
+ return true;
+ }
+}
+
+enum BorosStrikeCaptainCondition 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 BorosStrikeCaptainWatcher.checkPlayer(game, source);
+ }
+
+ @Override
+ public String toString() {
+ return "you attacked with three or more creatures this turn";
+ }
+}
+
+class BorosStrikeCaptainWatcher extends Watcher {
+
+ private final Map> map = new HashMap<>();
+
+ BorosStrikeCaptainWatcher() {
+ super(WatcherScope.GAME);
+ }
+
+ @Override
+ public void watch(GameEvent event, Game game) {
+ if (event.getType() != GameEvent.EventType.ATTACKER_DECLARED) {
+ return;
+ }
+ Optional.ofNullable(event)
+ .map(GameEvent::getTargetId)
+ .map(game::getPermanent)
+ .ifPresent(permanent -> map
+ .computeIfAbsent(permanent.getControllerId(), x -> new HashSet<>())
+ .add(new MageObjectReference(permanent, game)));
+
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ map.clear();
+ }
+
+ static boolean checkPlayer(Game game, Ability source) {
+ return game
+ .getState()
+ .getWatcher(BorosStrikeCaptainWatcher.class)
+ .map
+ .getOrDefault(source.getControllerId(), Collections.emptySet())
+ .size() >= 3;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/b/BortukBonerattle.java b/Mage.Sets/src/mage/cards/b/BortukBonerattle.java
index 1d7bb539f7b..53242931f0c 100644
--- a/Mage.Sets/src/mage/cards/b/BortukBonerattle.java
+++ b/Mage.Sets/src/mage/cards/b/BortukBonerattle.java
@@ -1,30 +1,29 @@
package mage.cards.b;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.dynamicvalue.common.DomainValue;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.abilities.hint.common.DomainHint;
import mage.cards.Card;
-import mage.constants.AbilityWord;
-import mage.constants.SubType;
-import mage.constants.SuperType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
+import mage.constants.AbilityWord;
import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.common.TargetCardInYourGraveyard;
+import java.util.UUID;
+
/**
- *
* @author weirddan455
*/
public final class BortukBonerattle extends CardImpl {
@@ -41,18 +40,12 @@ public final class BortukBonerattle extends CardImpl {
// Domain — When Bortuk Bonerattle enters the battlefield, if you cast it, choose target creature card in your graveyard.
// Return that card to the battlefield if its mana value is less than or equal to the number of basic land types among lands you control.
// Otherwise, put it into your hand.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(
- new ReturnFromGraveyardToBattlefieldTargetEffect(),
- new ReturnFromGraveyardToHandTargetEffect(),
- BortukBonerattleCondition.instance,
- null
- )),
- CastFromEverywhereSourceCondition.instance,
- "When {this} enters, if you cast it, choose target creature card in your graveyard. " +
- "Return that card to the battlefield if its mana value is less than or equal to the number of basic land types among lands you control. " +
- "Otherwise, put it into your hand."
- );
+ Ability ability = new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(
+ new ReturnFromGraveyardToBattlefieldTargetEffect(), new ReturnFromGraveyardToHandTargetEffect(),
+ BortukBonerattleCondition.instance, "choose target creature card in your graveyard. " +
+ "Return that card to the battlefield if its mana value is less than or equal to " +
+ "the number of basic land types among lands you control. Otherwise, put it into your hand."
+ )).withInterveningIf(CastFromEverywhereSourceCondition.instance);
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
ability.addHint(DomainHint.instance);
ability.setAbilityWord(AbilityWord.DOMAIN);
diff --git a/Mage.Sets/src/mage/cards/b/BoundaryLandsRanger.java b/Mage.Sets/src/mage/cards/b/BoundaryLandsRanger.java
index db8efb5c5d7..ff8377a9320 100644
--- a/Mage.Sets/src/mage/cards/b/BoundaryLandsRanger.java
+++ b/Mage.Sets/src/mage/cards/b/BoundaryLandsRanger.java
@@ -1,13 +1,12 @@
package mage.cards.b;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.condition.common.FerociousCondition;
import mage.abilities.costs.common.DiscardCardCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.hint.common.FerociousHint;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -29,14 +28,9 @@ public final class BoundaryLandsRanger extends CardImpl {
this.toughness = new MageInt(2);
// At the beginning of combat on your turn, if you control a creature with power 4 or greater, you may discard a card. If you do, draw a card.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- new DoIfCostPaid(
- new DrawCardSourceControllerEffect(1), new DiscardCardCost()
- )
- ), FerociousCondition.instance, "At the beginning of combat on your turn, if you control " +
- "a creature with power 4 or greater, you may discard a card. If you do, draw a card."
- ).addHint(FerociousHint.instance));
+ this.addAbility(new BeginningOfCombatTriggeredAbility(new DoIfCostPaid(
+ new DrawCardSourceControllerEffect(1), new DiscardCardCost()
+ )).withInterveningIf(FerociousCondition.instance).addHint(FerociousHint.instance));
}
private BoundaryLandsRanger(final BoundaryLandsRanger card) {
diff --git a/Mage.Sets/src/mage/cards/b/BounteousKirin.java b/Mage.Sets/src/mage/cards/b/BounteousKirin.java
index aa4cb58e370..eb6700bb3cb 100644
--- a/Mage.Sets/src/mage/cards/b/BounteousKirin.java
+++ b/Mage.Sets/src/mage/cards/b/BounteousKirin.java
@@ -33,7 +33,7 @@ public final class BounteousKirin extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast a Spirit or Arcane spell, you may gain life equal to that spell's converted mana cost.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new BounteousKirinEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD,
+ new BounteousKirinEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE,
true, SetTargetPointer.SPELL
));
}
diff --git a/Mage.Sets/src/mage/cards/b/BountyOfSkemfar.java b/Mage.Sets/src/mage/cards/b/BountyOfSkemfar.java
index 03729cb3666..f364d7ddfaa 100644
--- a/Mage.Sets/src/mage/cards/b/BountyOfSkemfar.java
+++ b/Mage.Sets/src/mage/cards/b/BountyOfSkemfar.java
@@ -48,8 +48,8 @@ class BountyOfSkemfarEffect extends OneShotEffect {
BountyOfSkemfarEffect() {
super(Outcome.Benefit);
- staticText = "reveal the top six cards of your library. You may put a land card from among them " +
- "onto the battlefield tapped and an Elf card from among them into your hand. " +
+ staticText = "reveal the top six cards of your library. You may put up to one land card from among them " +
+ "onto the battlefield tapped and up to one Elf card from among them into your hand. " +
"Put the rest on the bottom of your library in a random order";
}
diff --git a/Mage.Sets/src/mage/cards/b/BoxingRing.java b/Mage.Sets/src/mage/cards/b/BoxingRing.java
index 84ffb7d9453..9c9fbb84a4a 100644
--- a/Mage.Sets/src/mage/cards/b/BoxingRing.java
+++ b/Mage.Sets/src/mage/cards/b/BoxingRing.java
@@ -14,7 +14,6 @@ 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.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
@@ -23,10 +22,10 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TreasureToken;
import mage.target.TargetPermanent;
+import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.HashSet;
-import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -75,19 +74,11 @@ enum BoxingRingPredicate implements ObjectSourcePlayerPredicate {
@Override
public boolean apply(ObjectSourcePlayer input, Game game) {
- return input
- .getObject()
- .getManaValue()
- == input
- .getSource()
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("permanentEnteringBattlefield"))
- .map(Permanent.class::cast)
- .filter(Objects::nonNull)
+ return CardUtil
+ .getEffectValueFromAbility(input.getSource(), "permanentEnteringBattlefield", Permanent.class)
.map(MageObject::getManaValue)
- .findFirst()
- .orElse(-1);
+ .filter(x -> x == input.getObject().getManaValue())
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/b/BraidsArisenNightmare.java b/Mage.Sets/src/mage/cards/b/BraidsArisenNightmare.java
index 54769817e1d..809a042df26 100644
--- a/Mage.Sets/src/mage/cards/b/BraidsArisenNightmare.java
+++ b/Mage.Sets/src/mage/cards/b/BraidsArisenNightmare.java
@@ -67,7 +67,7 @@ class BraidsArisenNightmareEffect extends OneShotEffect {
public BraidsArisenNightmareEffect() {
super(Outcome.Sacrifice);
this.staticText = "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. " +
+ "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";
}
diff --git a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java
index 8700a24950f..16459284827 100644
--- a/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java
+++ b/Mage.Sets/src/mage/cards/b/BrasssTunnelGrinder.java
@@ -1,8 +1,8 @@
package mage.cards.b;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.DescendedThisTurnCondition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
@@ -12,6 +12,7 @@ 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.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -30,6 +31,8 @@ import java.util.UUID;
*/
public final class BrasssTunnelGrinder extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.BORE, 3);
+
public BrasssTunnelGrinder(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}");
this.secondSideCardClazz = mage.cards.t.TecutlanTheSearingRift.class;
@@ -45,14 +48,10 @@ public final class BrasssTunnelGrinder extends CardImpl {
TargetController.YOU, new AddCountersSourceEffect(CounterType.BORE.createInstance()),
false, DescendedThisTurnCondition.instance
);
-
- ConditionalOneShotEffect secondCheck = new ConditionalOneShotEffect(
- new RemoveAllCountersSourceEffect(CounterType.BORE),
- new SourceHasCounterCondition(CounterType.BORE, 3, Integer.MAX_VALUE),
+ ability.addEffect(new ConditionalOneShotEffect(
+ new RemoveAllCountersSourceEffect(CounterType.BORE), condition,
"Then if there are three or more bore counters on it, remove those counters and transform it"
- );
- secondCheck.addEffect(new TransformSourceEffect());
- ability.addEffect(secondCheck);
+ ).addEffect(new TransformSourceEffect()));
ability.addHint(DescendedThisTurnCount.getHint());
this.addAbility(ability, new DescendedWatcher());
}
diff --git a/Mage.Sets/src/mage/cards/b/BrazenCannonade.java b/Mage.Sets/src/mage/cards/b/BrazenCannonade.java
index 1c37415cb3d..b0e990ee842 100644
--- a/Mage.Sets/src/mage/cards/b/BrazenCannonade.java
+++ b/Mage.Sets/src/mage/cards/b/BrazenCannonade.java
@@ -1,13 +1,11 @@
package mage.cards.b;
-import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.condition.common.RaidCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect;
import mage.abilities.hint.common.RaidHint;
+import mage.abilities.triggers.BeginningOfPostcombatMainTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
@@ -42,16 +40,11 @@ public final class BrazenCannonade extends CardImpl {
));
// Raid -- At the beginning of your postcombat main phase, if you attacked with a creature this turn, exile the top card of your library. Until end of combat on your next turn, you may play that card.
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfPostcombatMainTriggeredAbility(
- new ExileTopXMayPlayUntilEffect(
- 1, Duration.UntilEndCombatOfYourNextTurn
- ), false
- ), RaidCondition.instance, "At the beginning of each of your postcombat main phases, " +
- "if you attacked this turn, exile the top card of your library. " +
- "Until end of combat on your next turn, you may play that card."
- );
- this.addAbility(ability.setAbilityWord(AbilityWord.RAID).addHint(RaidHint.instance), new PlayerAttackedWatcher());
+ this.addAbility(new BeginningOfPostcombatMainTriggeredAbility(
+ new ExileTopXMayPlayUntilEffect(1, Duration.UntilEndCombatOfYourNextTurn), false
+ ).withInterveningIf(RaidCondition.instance)
+ .setAbilityWord(AbilityWord.RAID)
+ .addHint(RaidHint.instance), new PlayerAttackedWatcher());
}
private BrazenCannonade(final BrazenCannonade card) {
diff --git a/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java b/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java
index 531bbb2f92a..4885b678e02 100644
--- a/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java
+++ b/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java
@@ -1,15 +1,10 @@
-
package mage.cards.b;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CastFromHandSourcePermanentCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect;
@@ -26,25 +21,25 @@ import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTargets;
import mage.watchers.common.CastFromHandWatcher;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
/**
- *
* @author LevelX2
*/
public final class BreachingLeviathan extends CardImpl {
public BreachingLeviathan(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{7}{U}{U}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{U}{U}");
this.subtype.add(SubType.LEVIATHAN);
this.power = new MageInt(9);
this.toughness = new MageInt(9);
// When Breaching Leviathan enters the battlefield, if you cast it from your hand, tap all nonblue creatures. Those creatures don't untap during their controllers' next untap steps.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new BreachingLeviathanEffect(), false),
- CastFromHandSourcePermanentCondition.instance,
- "When {this} enters, if you cast it from your hand, tap all nonblue creatures. Those creatures don't untap during their controllers' next untap steps."),
- new CastFromHandWatcher());
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new BreachingLeviathanEffect(), false)
+ .withInterveningIf(CastFromHandSourcePermanentCondition.instance), new CastFromHandWatcher());
}
private BreachingLeviathan(final BreachingLeviathan card) {
diff --git a/Mage.Sets/src/mage/cards/b/BriarknitKami.java b/Mage.Sets/src/mage/cards/b/BriarknitKami.java
index fedf9683a7a..961faa6a646 100644
--- a/Mage.Sets/src/mage/cards/b/BriarknitKami.java
+++ b/Mage.Sets/src/mage/cards/b/BriarknitKami.java
@@ -27,7 +27,7 @@ public final class BriarknitKami extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, put a +1/+1 counter on target creature.
- Ability ability = new SpellCastControllerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/b/BringerOfTheLastGift.java b/Mage.Sets/src/mage/cards/b/BringerOfTheLastGift.java
index 2c68a8553a2..a0972727acc 100644
--- a/Mage.Sets/src/mage/cards/b/BringerOfTheLastGift.java
+++ b/Mage.Sets/src/mage/cards/b/BringerOfTheLastGift.java
@@ -4,7 +4,6 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
@@ -39,12 +38,8 @@ public final class BringerOfTheLastGift extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Bringer of the Last Gift enters the battlefield, if you cast it, each player sacrifices all other creatures they control. Then each player returns all creature cards from their graveyard that weren't put there this way to the battlefield.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new BringerOfTheLastGiftEffect()),
- CastFromEverywhereSourceCondition.instance,
- "When {this} enters, if you cast it, each player sacrifices all other creatures they control. "
- + "Then each player returns all creature cards from their graveyard that weren't put there this way to the battlefield."
- ));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new BringerOfTheLastGiftEffect())
+ .withInterveningIf(CastFromEverywhereSourceCondition.instance));
}
private BringerOfTheLastGift(final BringerOfTheLastGift card) {
@@ -61,6 +56,9 @@ class BringerOfTheLastGiftEffect extends OneShotEffect {
BringerOfTheLastGiftEffect() {
super(Outcome.Benefit);
+ staticText = "each player sacrifices all other creatures they control. " +
+ "Then each player returns all creature cards from their graveyard " +
+ "that weren't put there this way to the battlefield";
}
private BringerOfTheLastGiftEffect(final BringerOfTheLastGiftEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/b/BudokaPupil.java b/Mage.Sets/src/mage/cards/b/BudokaPupil.java
index 672c00d9b22..1abf18db01e 100644
--- a/Mage.Sets/src/mage/cards/b/BudokaPupil.java
+++ b/Mage.Sets/src/mage/cards/b/BudokaPupil.java
@@ -3,35 +3,35 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.TrampleAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
- *
* @author LevelX2
*/
public final class BudokaPupil extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.KI, 2);
+
public BudokaPupil(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}");
this.subtype.add(SubType.HUMAN, SubType.MONK);
this.power = new MageInt(2);
@@ -40,13 +40,12 @@ public final class BudokaPupil extends CardImpl {
this.flipCardName = "Ichiga, Who Topples Oaks";
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Budoka Pupil.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// At the beginning of the end step, if there are two or more ki counters on Budoka Pupil, you may flip it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new IchigaWhoTopplesOaks()), true),
- new SourceHasCounterCondition(CounterType.KI, 2, Integer.MAX_VALUE),
- "At the beginning of the end step, if there are two or more ki counters on {this}, you may flip it."));
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.NEXT, new FlipSourceEffect(new IchigaWhoTopplesOaks()).setText("flip it"), true, condition
+ ));
}
private BudokaPupil(final BudokaPupil card) {
@@ -80,6 +79,7 @@ class IchigaWhoTopplesOaks extends TokenImpl {
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
+
private IchigaWhoTopplesOaks(final IchigaWhoTopplesOaks token) {
super(token);
}
diff --git a/Mage.Sets/src/mage/cards/b/BushyBodyguard.java b/Mage.Sets/src/mage/cards/b/BushyBodyguard.java
index aa6f98136c0..57daacd29e6 100644
--- a/Mage.Sets/src/mage/cards/b/BushyBodyguard.java
+++ b/Mage.Sets/src/mage/cards/b/BushyBodyguard.java
@@ -32,7 +32,7 @@ public final class BushyBodyguard extends CardImpl {
// When this creature enters, you may forage. If you do, put two +1/+1 counters on it.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid(
- new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ForageCost()
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)).setText("put two +1/+1 counters on it"), new ForageCost()
)));
}
diff --git a/Mage.Sets/src/mage/cards/c/CabalPaladin.java b/Mage.Sets/src/mage/cards/c/CabalPaladin.java
index 5f47303d4e7..ccb8d01a016 100644
--- a/Mage.Sets/src/mage/cards/c/CabalPaladin.java
+++ b/Mage.Sets/src/mage/cards/c/CabalPaladin.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
/**
*
@@ -32,7 +32,7 @@ public final class CabalPaladin extends CardImpl {
this.addAbility(new SpellCastControllerTriggeredAbility(
new DamagePlayersEffect(Outcome.Damage, StaticValue.get(2), TargetController.OPPONENT)
.setText("{this} deals 2 damage to each opponent. (Artifacts, legendaries, and Sagas are historic.)"),
- new FilterHistoricSpell(), false
+ StaticFilters.FILTER_SPELL_HISTORIC, false
));
}
diff --git a/Mage.Sets/src/mage/cards/c/CallowJushi.java b/Mage.Sets/src/mage/cards/c/CallowJushi.java
index 87636c0c55e..2abe3c35a17 100644
--- a/Mage.Sets/src/mage/cards/c/CallowJushi.java
+++ b/Mage.Sets/src/mage/cards/c/CallowJushi.java
@@ -1,37 +1,37 @@
-
package mage.cards.c;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.CounterUnlessPaysEffect;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+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.Zone;
+import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
import mage.target.TargetSpell;
+import java.util.UUID;
+
/**
- *
* @author LevelX2
*/
public final class CallowJushi extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.KI, 2);
+
public CallowJushi(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}");
this.subtype.add(SubType.HUMAN);
@@ -43,13 +43,12 @@ public final class CallowJushi extends CardImpl {
this.flipCardName = "Jaraku the Interloper";
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Callow Jushi.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// At the beginning of the end step, if there are two or more ki counters on Callow Jushi, you may flip it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new JarakuTheInterloper()), true),
- new SourceHasCounterCondition(CounterType.KI, 2, Integer.MAX_VALUE),
- "At the beginning of the end step, if there are two or more ki counters on {this}, you may flip it."));
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.NEXT, new FlipSourceEffect(new JarakuTheInterloper()).setText("flip it"), true, condition
+ ));
}
private CallowJushi(final CallowJushi card) {
@@ -80,6 +79,7 @@ class JarakuTheInterloper extends TokenImpl {
ability.addTarget(new TargetSpell());
this.addAbility(ability);
}
+
private JarakuTheInterloper(final JarakuTheInterloper token) {
super(token);
}
diff --git a/Mage.Sets/src/mage/cards/c/CausticWasps.java b/Mage.Sets/src/mage/cards/c/CausticWasps.java
index b7b6fb7f341..cf2c5bf75e7 100644
--- a/Mage.Sets/src/mage/cards/c/CausticWasps.java
+++ b/Mage.Sets/src/mage/cards/c/CausticWasps.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -37,7 +37,7 @@ public final class CausticWasps extends CardImpl {
// Whenever Caustic Wasps deals combat damage to a player, you may destroy target artifact that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/c/CelestialKirin.java b/Mage.Sets/src/mage/cards/c/CelestialKirin.java
index a385158f633..40b576b47ab 100644
--- a/Mage.Sets/src/mage/cards/c/CelestialKirin.java
+++ b/Mage.Sets/src/mage/cards/c/CelestialKirin.java
@@ -36,7 +36,7 @@ public final class CelestialKirin extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast a Spirit or Arcane spell, destroy all permanents with that spell's converted mana cost.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new CelestialKirinEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD,
+ new CelestialKirinEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE,
false, SetTargetPointer.SPELL
));
}
diff --git a/Mage.Sets/src/mage/cards/c/Chainsaw.java b/Mage.Sets/src/mage/cards/c/Chainsaw.java
index 8477a05584a..9dbc3fa349a 100644
--- a/Mage.Sets/src/mage/cards/c/Chainsaw.java
+++ b/Mage.Sets/src/mage/cards/c/Chainsaw.java
@@ -43,7 +43,8 @@ public final class Chainsaw extends CardImpl {
StaticFilters.FILTER_PERMANENT_CREATURES, false));
// Equipped creature gets +X/+0, where X is the number of rev counters on Chainsaw.
- this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(xValue, StaticValue.get(0))));
+ this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(xValue, StaticValue.get(0))
+ .setText("equipped creature gets +X/+0, where X is the number of rev counters on {this}")));
// Equip {3}
this.addAbility(new EquipAbility(3, false));
diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java
index 8f436e29e57..f809074e503 100644
--- a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java
+++ b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java
@@ -1,36 +1,37 @@
-
package mage.cards.c;
-import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.condition.common.MoreThanStartingLifeTotalCondition;
import mage.abilities.costs.common.TapSourceCost;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.decorator.ConditionalOneShotEffect;
+import mage.abilities.effects.common.GainLifeEffect;
+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.Outcome;
-import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
-import mage.players.Player;
+
+import java.util.UUID;
/**
- *
* @author intimidatingant
*/
public final class ChaliceOfLife extends CardImpl {
public ChaliceOfLife(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
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.
- this.addAbility(new SimpleActivatedAbility(new ChaliceOfLifeEffect(), new TapSourceCost()));
+ 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);
}
private ChaliceOfLife(final ChaliceOfLife card) {
@@ -42,39 +43,3 @@ public final class ChaliceOfLife extends CardImpl {
return new ChaliceOfLife(this);
}
}
-
-class ChaliceOfLifeEffect extends OneShotEffect {
-
- ChaliceOfLifeEffect() {
- super(Outcome.GainLife);
- staticText = "You gain 1 life. Then if you have at least 10 life more than your starting life total, transform Chalice of Life";
- }
-
- private ChaliceOfLifeEffect(final ChaliceOfLifeEffect effect) {
- super(effect);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent permanent = game.getPermanent(source.getSourceId());
- if (permanent != null) {
- Player player = game.getPlayer(source.getControllerId());
- if(player != null) {
- //gain 1 life
- player.gainLife(1, game, source);
-
- // if you have at least 10 life more than your starting life total, transform Chalice of Life.
- if (player.getLife() >= game.getStartingLife() + 10) {
- permanent.transform(source, game);
- }
- }
- }
- return false;
- }
-
- @Override
- public ChaliceOfLifeEffect copy() {
- return new ChaliceOfLifeEffect(this);
- }
-
-}
diff --git a/Mage.Sets/src/mage/cards/c/CharitableLevy.java b/Mage.Sets/src/mage/cards/c/CharitableLevy.java
index b814b907ea6..bbc6d4a8e7a 100644
--- a/Mage.Sets/src/mage/cards/c/CharitableLevy.java
+++ b/Mage.Sets/src/mage/cards/c/CharitableLevy.java
@@ -37,7 +37,7 @@ public final class CharitableLevy extends CardImpl {
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
- private static final Condition condition = new SourceHasCounterCondition(CounterType.COLLECTION, 3, Integer.MAX_VALUE);
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.COLLECTION, 3);
private static final FilterCard filterPlains = new FilterBySubtypeCard(SubType.PLAINS);
diff --git a/Mage.Sets/src/mage/cards/c/ClementTheWorrywort.java b/Mage.Sets/src/mage/cards/c/ClementTheWorrywort.java
index baf0b1530ae..558cfab74e0 100644
--- a/Mage.Sets/src/mage/cards/c/ClementTheWorrywort.java
+++ b/Mage.Sets/src/mage/cards/c/ClementTheWorrywort.java
@@ -15,30 +15,38 @@ import mage.abilities.mana.builder.ConditionalManaBuilder;
import mage.abilities.mana.conditional.CreatureCastManaCondition;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.constants.SuperType;
import mage.filter.Filter;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
-import mage.filter.predicate.mageobject.ManaValuePredicate;
+import mage.filter.predicate.ObjectSourcePlayer;
+import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
+import mage.util.CardUtil;
import java.util.UUID;
/**
- *
* @author earchip94
*/
public final class ClementTheWorrywort extends CardImpl {
+ private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creature you control with lesser mana value");
private static final FilterPermanent frogFilter = new FilterPermanent(SubType.FROG, "Frogs");
+ static {
+ filter.add(ClementTheWorrywortPredicate.instance);
+ }
+
public ClementTheWorrywort(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}");
-
+
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.FROG);
this.subtype.add(SubType.DRUID);
@@ -49,12 +57,16 @@ public final class ClementTheWorrywort extends CardImpl {
this.addAbility(VigilanceAbility.getInstance());
// Whenever Clement, the Worrywort or another creature you control enters, return up to one target creature you control with lesser mana value to its owner's hand.
- this.addAbility(new ClementTheWorrywortTriggeredAbility());
+ Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility(
+ new ReturnToHandTargetEffect(), StaticFilters.FILTER_CONTROLLED_CREATURE, false, false
+ );
+ ability.addTarget(new TargetPermanent(0, 1, filter));
+ this.addAbility(ability);
// Frogs you control have "{T}: Add {G} or {U}. Spend this mana only to cast a creature spell."
Ability gMana = new ConditionalColoredManaAbility(new TapSourceCost(), Mana.GreenMana(1), new ClementTheWorrywortManaBuilder());
Ability bMana = new ConditionalColoredManaAbility(new TapSourceCost(), Mana.BlueMana(1), new ClementTheWorrywortManaBuilder());
- Ability ability = new SimpleStaticAbility(
+ ability = new SimpleStaticAbility(
new GainAbilityControlledEffect(gMana, Duration.WhileOnBattlefield, frogFilter, false)
.setText("Frogs you control have \"{T}: Add {G} or {U}.")
);
@@ -75,40 +87,17 @@ public final class ClementTheWorrywort extends CardImpl {
}
}
-class ClementTheWorrywortTriggeredAbility extends EntersBattlefieldThisOrAnotherTriggeredAbility {
-
- ClementTheWorrywortTriggeredAbility() {
- super(new ReturnToHandTargetEffect().setText("return up to one target creature you control with lesser mana value to its owner's hand"),
- StaticFilters.FILTER_PERMANENT_CREATURE, false, true);
- }
-
- ClementTheWorrywortTriggeredAbility(final ClementTheWorrywortTriggeredAbility ability) {
- super(ability);
- }
+enum ClementTheWorrywortPredicate implements ObjectSourcePlayerPredicate {
+ instance;
@Override
- public ClementTheWorrywortTriggeredAbility copy() {
- return new ClementTheWorrywortTriggeredAbility(this);
+ public boolean apply(ObjectSourcePlayer input, Game game) {
+ return CardUtil.getEffectValueFromAbility(
+ input.getSource(), "permanentEnteringBattlefield", Permanent.class
+ )
+ .filter(permanent -> input.getObject().getManaValue() < permanent.getManaValue())
+ .isPresent();
}
-
- @Override
- public boolean checkTrigger(GameEvent event, Game game) {
- if (super.checkTrigger(event, game)) {
- this.getTargets().clear();
- Permanent permanent = game.getPermanent(event.getTargetId());
- if (permanent == null) {
- return false;
- }
- int mv = permanent.getManaValue();
- FilterControlledCreaturePermanent filter =
- new FilterControlledCreaturePermanent("creature you control with mana value " + (mv - 1) + " or less");
- filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, mv));
- this.addTarget(new TargetPermanent(0,1, filter));
- return true;
- }
- return false;
- }
-
}
class ClementTheWorrywortConditionalMana extends ConditionalMana {
diff --git a/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java b/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java
index 2bb33d307e4..696872e5154 100644
--- a/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java
+++ b/Mage.Sets/src/mage/cards/c/CloudhoofKirin.java
@@ -35,7 +35,7 @@ public final class CloudhoofKirin extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast a Spirit or Arcane spell, you may have target player put the top X cards of their library into their graveyard, where X is that spell's converted mana cost.
- Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new CloudhoofKirinEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true, SetTargetPointer.SPELL);
+ Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new CloudhoofKirinEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true, SetTargetPointer.SPELL);
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/c/Cocoon.java b/Mage.Sets/src/mage/cards/c/Cocoon.java
index 9f75b0963b4..4a8d9da05ac 100644
--- a/Mage.Sets/src/mage/cards/c/Cocoon.java
+++ b/Mage.Sets/src/mage/cards/c/Cocoon.java
@@ -46,12 +46,12 @@ public final class Cocoon extends CardImpl {
// When Cocoon enters the battlefield, tap enchanted creature and put three pupa counters on Cocoon.
Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect());
- ability.addEffect(new AddCountersSourceEffect(CounterType.PUPA.createInstance(3)));
+ ability.addEffect(new AddCountersSourceEffect(CounterType.PUPA.createInstance(3)).concatBy("and"));
this.addAbility(ability);
// Enchanted creature doesn’t untap during your untap step if Cocoon has a pupa counter on it.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(),
- new SourceHasCounterCondition(CounterType.PUPA)).setText("Enchanted creature doesn't untap during its controller's untap step if Cocoon has a pupa counter on it")));
+ new SourceHasCounterCondition(CounterType.PUPA)).setText("Enchanted creature doesn't untap during your untap step if {this} has a pupa counter on it")));
// At the beginning of your upkeep, remove a pupa counter from Cocoon. If you can’t, sacrifice it, put a +1/+1 counter on enchanted creature, and that creature gains flying.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CocoonEffect()));
diff --git a/Mage.Sets/src/mage/cards/c/CollisionCourse.java b/Mage.Sets/src/mage/cards/c/CollisionCourse.java
index a638e55c259..d33a6607735 100644
--- a/Mage.Sets/src/mage/cards/c/CollisionCourse.java
+++ b/Mage.Sets/src/mage/cards/c/CollisionCourse.java
@@ -42,7 +42,9 @@ public final class CollisionCourse extends CardImpl {
// Choose one --
// * Collision Course deals X damage to target creature, where X is the number of permanents you control that are creatures and/or Vehicles.
- this.getSpellAbility().addEffect(new DamageTargetEffect(xValue));
+ this.getSpellAbility().addEffect(new DamageTargetEffect(xValue)
+ .setText("{this} deals X damage to target creature, where X is " +
+ "the number of permanents you control that are creatures and/or Vehicles"));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addHint(hint);
diff --git a/Mage.Sets/src/mage/cards/c/ComboAttack.java b/Mage.Sets/src/mage/cards/c/ComboAttack.java
index b426489e07b..2b17b496161 100644
--- a/Mage.Sets/src/mage/cards/c/ComboAttack.java
+++ b/Mage.Sets/src/mage/cards/c/ComboAttack.java
@@ -55,20 +55,21 @@ class ComboAttackEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- if (source.getTargets().size() < 2 || source.getTargets().get(0).getTargets().size() < 2) {
+ if (source.getTargets().size() < 2) {
return false;
}
- Permanent permanent1 = game.getPermanent(source.getTargets().get(0).getTargets().get(0));
- Permanent permanent2 = game.getPermanent(source.getTargets().get(0).getTargets().get(1));
Permanent permanent3 = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (permanent3 == null) {
return false;
}
- if (permanent1 != null) {
- permanent3.damage(permanent1.getPower().getValue(), permanent1.getId(), source, game, false, true);
- }
- if (permanent2 != null) {
- permanent3.damage(permanent2.getPower().getValue(), permanent2.getId(), source, game, false, true);
+ // You can’t cast Combo Attack without targeting two creatures your team controls.
+ // If one of those creatures is an illegal target as Combo Attack resolves,
+ // the other will still deal damage equal to its power. (2018-06-08)
+ for (UUID id : source.getTargets().get(0).getTargets()) {
+ Permanent permanent = game.getPermanent(id);
+ if (permanent != null) {
+ permanent3.damage(permanent.getPower().getValue(), permanent.getId(), source, game);
+ }
}
return true;
}
diff --git a/Mage.Sets/src/mage/cards/c/CommanderLiaraPortyr.java b/Mage.Sets/src/mage/cards/c/CommanderLiaraPortyr.java
new file mode 100644
index 00000000000..ee037b68bc7
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/c/CommanderLiaraPortyr.java
@@ -0,0 +1,120 @@
+package mage.cards.c;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.cost.CostModificationEffectImpl;
+import mage.cards.*;
+import mage.constants.*;
+import mage.game.Game;
+import mage.game.stack.Spell;
+import mage.players.Player;
+import mage.util.CardUtil;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class CommanderLiaraPortyr extends CardImpl {
+
+ public CommanderLiaraPortyr(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{W}");
+
+ this.supertype.add(SuperType.LEGENDARY);
+ this.subtype.add(SubType.HUMAN);
+ this.subtype.add(SubType.SOLDIER);
+ this.power = new MageInt(5);
+ this.toughness = new MageInt(3);
+
+ // Whenever you attack, spells you cast from exile this turn cost {X} less to cast, where X is the number of players being attacked. Exile the top X cards of your library. Until end of turn, you may cast spells from among those exiled cards.
+ Ability ability = new AttacksWithCreaturesTriggeredAbility(new CommanderLiaraPortyrCostEffect(), 1);
+ ability.addEffect(new CommanderLiaraPortyrExileEffect());
+ this.addAbility(ability);
+ }
+
+ private CommanderLiaraPortyr(final CommanderLiaraPortyr card) {
+ super(card);
+ }
+
+ @Override
+ public CommanderLiaraPortyr copy() {
+ return new CommanderLiaraPortyr(this);
+ }
+}
+
+class CommanderLiaraPortyrCostEffect extends CostModificationEffectImpl {
+
+ CommanderLiaraPortyrCostEffect() {
+ super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.REDUCE_COST);
+ staticText = "spells you cast from exile this turn cost {X} less to cast, " +
+ "where X is the number of players being attacked";
+ }
+
+ private CommanderLiaraPortyrCostEffect(final CommanderLiaraPortyrCostEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public CommanderLiaraPortyrCostEffect copy() {
+ return new CommanderLiaraPortyrCostEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source, Ability abilityToModify) {
+ Optional.ofNullable((Integer) getValue(AttacksWithCreaturesTriggeredAbility.VALUEKEY_NUMBER_DEFENDING_PLAYERS))
+ .ifPresent(i -> CardUtil.reduceCost(abilityToModify, 1));
+ return true;
+ }
+
+ @Override
+ public boolean applies(Ability abilityToModify, Ability source, Game game) {
+ return Optional
+ .ofNullable(abilityToModify)
+ .map(Ability::getSourceId)
+ .map(game::getSpell)
+ .map(Spell::getFromZone)
+ .filter(Zone.EXILED::match)
+ .isPresent();
+ }
+}
+
+class CommanderLiaraPortyrExileEffect extends OneShotEffect {
+
+ CommanderLiaraPortyrExileEffect() {
+ super(Outcome.Benefit);
+ staticText = "Exile the top X cards of your library. Until end of turn, " +
+ "you may cast spells from among those exiled cards";
+ }
+
+ private CommanderLiaraPortyrExileEffect(final CommanderLiaraPortyrExileEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public CommanderLiaraPortyrExileEffect copy() {
+ return new CommanderLiaraPortyrExileEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player player = game.getPlayer(source.getControllerId());
+ int count = Optional.ofNullable((Integer) getValue(
+ AttacksWithCreaturesTriggeredAbility.VALUEKEY_NUMBER_DEFENDING_PLAYERS
+ )).orElse(0);
+ if (player == null || count < 1) {
+ return true;
+ }
+ Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, count));
+ if (cards.isEmpty()) {
+ return false;
+ }
+ player.moveCards(cards, Zone.EXILED, source, game);
+ for (Card card : cards.getCards(game)) {
+ CardUtil.makeCardPlayable(game, source, card, true, Duration.EndOfTurn, false);
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/c/CommandoRaid.java b/Mage.Sets/src/mage/cards/c/CommandoRaid.java
index be0b73f7b6c..c0d604217ac 100644
--- a/Mage.Sets/src/mage/cards/c/CommandoRaid.java
+++ b/Mage.Sets/src/mage/cards/c/CommandoRaid.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -29,7 +29,7 @@ public final class CommandoRaid extends CardImpl {
effect.setText("have it deal damage equal to its power to target creature that player controls.");
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, true, true);
ability.addTarget(new TargetCreaturePermanent());
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(
ability, Duration.EndOfTurn,
diff --git a/Mage.Sets/src/mage/cards/c/CommunalBrewing.java b/Mage.Sets/src/mage/cards/c/CommunalBrewing.java
index 506ad83fdf7..a2e0ec724c7 100644
--- a/Mage.Sets/src/mage/cards/c/CommunalBrewing.java
+++ b/Mage.Sets/src/mage/cards/c/CommunalBrewing.java
@@ -95,7 +95,7 @@ class CommunalBrewingCountersEffect extends ReplacementEffectImpl {
CommunalBrewingCountersEffect() {
super(Duration.EndOfTurn, Outcome.BoostCreature);
- this.staticText = "that creature enters with X additional +1/+1 counters on it, where X is is the number of ingredient counters on {this}";
+ this.staticText = "that creature enters with X additional +1/+1 counters on it, where X is the number of ingredient counters on {this}";
}
private CommunalBrewingCountersEffect(final CommunalBrewingCountersEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/c/CourageousResolve.java b/Mage.Sets/src/mage/cards/c/CourageousResolve.java
index 361f8523223..b3719ad8181 100644
--- a/Mage.Sets/src/mage/cards/c/CourageousResolve.java
+++ b/Mage.Sets/src/mage/cards/c/CourageousResolve.java
@@ -1,4 +1,3 @@
-
package mage.cards.c;
import mage.MageObject;
@@ -15,9 +14,7 @@ import mage.abilities.keyword.ProtectionAbility;
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.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -46,9 +43,9 @@ public final class CourageousResolve extends CardImpl {
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("Draw a card. (It can't be blocked, targeted, dealt damage, enchanted, or equipped by anything controlled by those players.)"));
- //Fateful hour — If you have 5 or less life, you can't lose life this turn, you can't lose the game this turn,
+ // Fateful hour — If you have 5 or less life, you can't lose life this turn, you can't lose the game this turn,
// and your opponents can't win the game this turn.
- this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new CantLoseLifeEffect(), FatefulHourCondition.instance, "
Fateful hour — If you have 5 or less life, you can't lose life this turn"));
+ this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new CourageousResolveCantLoseLifeEffect(), FatefulHourCondition.instance, "
Fateful hour — If you have 5 or less life, you can't lose life this turn"));
this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect(new CourageousResolveWinLoseEffect(), FatefulHourCondition.instance));
@@ -132,19 +129,19 @@ class CourageousResolveProtectionAbility extends ProtectionAbility {
}
}
-class CantLoseLifeEffect extends ContinuousEffectImpl {
+class CourageousResolveCantLoseLifeEffect extends ContinuousEffectImpl {
- public CantLoseLifeEffect() {
- super(Duration.EndOfTurn, Outcome.Benefit);
+ CourageousResolveCantLoseLifeEffect() {
+ super(Duration.EndOfTurn, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
}
- protected CantLoseLifeEffect(final CantLoseLifeEffect effect) {
+ protected CourageousResolveCantLoseLifeEffect(final CourageousResolveCantLoseLifeEffect effect) {
super(effect);
}
@Override
- public CantLoseLifeEffect copy() {
- return new CantLoseLifeEffect(this);
+ public CourageousResolveCantLoseLifeEffect copy() {
+ return new CourageousResolveCantLoseLifeEffect(this);
}
@Override
@@ -154,7 +151,7 @@ class CantLoseLifeEffect extends ContinuousEffectImpl {
player.setCanLoseLife(false);
return true;
}
- return true;
+ return false;
}
}
diff --git a/Mage.Sets/src/mage/cards/c/CovetousElegy.java b/Mage.Sets/src/mage/cards/c/CovetousElegy.java
new file mode 100644
index 00000000000..9d088f7a114
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/c/CovetousElegy.java
@@ -0,0 +1,92 @@
+package mage.cards.c;
+
+import mage.abilities.Ability;
+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.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.filter.StaticFilters;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.game.permanent.token.TreasureToken;
+import mage.players.Player;
+import mage.target.TargetPermanent;
+import mage.target.common.TargetControlledCreaturePermanent;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class CovetousElegy extends CardImpl {
+
+ private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE);
+ private static final Hint hint = new ValueHint("Creatures your opponents control", xValue);
+
+ public CovetousElegy(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{B}");
+
+ // Each player chooses up to two creatures they control, then sacrifices the rest. Then you create a tapped Treasure token for each creature your opponents control.
+ this.getSpellAbility().addEffect(new CovetousElegyEffect());
+ this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken(), xValue).concatBy("Then"));
+ this.getSpellAbility().addHint(hint);
+ }
+
+ private CovetousElegy(final CovetousElegy card) {
+ super(card);
+ }
+
+ @Override
+ public CovetousElegy copy() {
+ return new CovetousElegy(this);
+ }
+}
+
+class CovetousElegyEffect extends OneShotEffect {
+
+ CovetousElegyEffect() {
+ super(Outcome.Benefit);
+ staticText = "each player chooses up to two creatures they control, then sacrifices the rest";
+ }
+
+ private CovetousElegyEffect(final CovetousElegyEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public CovetousElegyEffect copy() {
+ return new CovetousElegyEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Set creatures = new HashSet<>();
+ for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
+ Player player = game.getPlayer(playerId);
+ if (player == null) {
+ continue;
+ }
+ TargetPermanent target = new TargetControlledCreaturePermanent(0, 2);
+ target.withNotTarget(true);
+ target.withChooseHint("the rest will be sacrificed");
+ player.choose(outcome, target, source, game);
+ creatures.addAll(target.getTargets());
+ }
+ for (Permanent permanent : game.getBattlefield().getActivePermanents(
+ StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game
+ )) {
+ if (!creatures.contains(permanent.getId())) {
+ permanent.sacrifice(source, game);
+ }
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/c/CryptidInspector.java b/Mage.Sets/src/mage/cards/c/CryptidInspector.java
index 2481532b2ff..f7caa7f7bb8 100644
--- a/Mage.Sets/src/mage/cards/c/CryptidInspector.java
+++ b/Mage.Sets/src/mage/cards/c/CryptidInspector.java
@@ -1,7 +1,5 @@
package mage.cards.c;
-import java.util.UUID;
-
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.TurnedFaceUpAllTriggeredAbility;
@@ -18,12 +16,14 @@ import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.card.FaceDownPredicate;
+import java.util.UUID;
+
/**
* @author jackd149
*/
public final class CryptidInspector extends CardImpl {
private static final FilterPermanent filter1 = new FilterPermanent("a face-down permanent");
- private static final FilterPermanent filter2 = new FilterControlledPermanent("Cryptid Inspector or another permanent you control");
+ private static final FilterPermanent filter2 = new FilterControlledPermanent();
static {
filter1.add(FaceDownPredicate.instance);
@@ -40,17 +40,17 @@ public final class CryptidInspector extends CardImpl {
// Whenever a face-down permanent you control enters and whenever Cryptid Inspector or another permanent you control is turned face up,
// put a +1/+1 counter on Cryptid Inspector.
this.addAbility(new OrTriggeredAbility(
- Zone.BATTLEFIELD,
- new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
- false,
- "Whenever a face-down permanent you control enters and "
- + "whenever Cryptid Inspector or another permanent you control is turned face up, ",
- new EntersBattlefieldControlledTriggeredAbility(null, filter1),
- new TurnedFaceUpAllTriggeredAbility(null, filter2)
+ Zone.BATTLEFIELD,
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
+ false,
+ "Whenever a face-down permanent you control enters and "
+ + "whenever {this} or another permanent you control is turned face up, ",
+ new EntersBattlefieldControlledTriggeredAbility(null, filter1),
+ new TurnedFaceUpAllTriggeredAbility(null, filter2)
));
}
- private CryptidInspector(final CryptidInspector card){
+ private CryptidInspector(final CryptidInspector card) {
super(card);
}
@@ -58,4 +58,4 @@ public final class CryptidInspector extends CardImpl {
public CryptidInspector copy() {
return new CryptidInspector(this);
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/c/CrystalSkullIsuSpyglass.java b/Mage.Sets/src/mage/cards/c/CrystalSkullIsuSpyglass.java
index 211e4f7b20e..e2805739d01 100644
--- a/Mage.Sets/src/mage/cards/c/CrystalSkullIsuSpyglass.java
+++ b/Mage.Sets/src/mage/cards/c/CrystalSkullIsuSpyglass.java
@@ -9,7 +9,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import java.util.UUID;
@@ -18,7 +18,10 @@ import java.util.UUID;
*/
public final class CrystalSkullIsuSpyglass extends CardImpl {
- private static final FilterCard filter = new FilterHistoricCard("play historic lands and cast historic spells");
+ private static final FilterCard filter = new FilterCard("play historic lands and cast historic spells");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
public CrystalSkullIsuSpyglass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}{U}");
diff --git a/Mage.Sets/src/mage/cards/c/CunningBandit.java b/Mage.Sets/src/mage/cards/c/CunningBandit.java
index 8c9d58f9f4b..47586c5af03 100644
--- a/Mage.Sets/src/mage/cards/c/CunningBandit.java
+++ b/Mage.Sets/src/mage/cards/c/CunningBandit.java
@@ -1,37 +1,33 @@
-
package mage.cards.c;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.CardType;
-import mage.constants.SubType;
-import mage.constants.Duration;
-import mage.constants.SuperType;
-import mage.constants.Zone;
+import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
import mage.target.common.TargetCreaturePermanent;
+import java.util.UUID;
+
/**
- *
* @author LevelX2
*/
public final class CunningBandit extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.KI, 2);
+
public CunningBandit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}");
this.subtype.add(SubType.HUMAN);
@@ -43,13 +39,12 @@ public final class CunningBandit extends CardImpl {
this.flipCardName = "Azamuki, Treachery Incarnate";
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Cunning Bandit.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// At the beginning of the end step, if there are two or more ki counters on Cunning Bandit, you may flip it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new AzamukiTreacheryIncarnate()), true),
- new SourceHasCounterCondition(CounterType.KI, 2, Integer.MAX_VALUE),
- "At the beginning of the end step, if there are two or more ki counters on {this}, you may flip it."));
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.NEXT, new FlipSourceEffect(new AzamukiTreacheryIncarnate()).setText("flip it"), true, condition
+ ));
}
private CunningBandit(final CunningBandit card) {
@@ -80,6 +75,7 @@ class AzamukiTreacheryIncarnate extends TokenImpl {
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
+
private AzamukiTreacheryIncarnate(final AzamukiTreacheryIncarnate token) {
super(token);
}
diff --git a/Mage.Sets/src/mage/cards/d/DaringWaverider.java b/Mage.Sets/src/mage/cards/d/DaringWaverider.java
index a253a60a4b5..09b1b6aa903 100644
--- a/Mage.Sets/src/mage/cards/d/DaringWaverider.java
+++ b/Mage.Sets/src/mage/cards/d/DaringWaverider.java
@@ -21,7 +21,7 @@ import java.util.UUID;
* @author notgreat
*/
public final class DaringWaverider extends CardImpl {
- private static final FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card with mana value 4 or less");
+ private static final FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card with mana value 4 or less from your graveyard");
static {
filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, 4));
diff --git a/Mage.Sets/src/mage/cards/d/DawningPurist.java b/Mage.Sets/src/mage/cards/d/DawningPurist.java
index b41e8c8ecf2..25fa10758d7 100644
--- a/Mage.Sets/src/mage/cards/d/DawningPurist.java
+++ b/Mage.Sets/src/mage/cards/d/DawningPurist.java
@@ -13,7 +13,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -36,7 +36,7 @@ public final class DawningPurist extends CardImpl {
// Whenever Dawning Purist deals combat damage to a player, you may destroy target enchantment that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
// Morph {1}{W}
diff --git a/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java b/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java
index 3726d9e2150..3b3e02f246c 100644
--- a/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java
+++ b/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java
@@ -58,7 +58,7 @@ class DeathmistRaptorEffect extends OneShotEffect {
DeathmistRaptorEffect() {
super(Outcome.Benefit);
- this.staticText = "you may return {this} from your graveyard to the battlefield face up or face down";
+ this.staticText = "you may return this card from your graveyard to the battlefield face up or face down";
}
private DeathmistRaptorEffect(final DeathmistRaptorEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/d/DecreeOfSilence.java b/Mage.Sets/src/mage/cards/d/DecreeOfSilence.java
index f0a6185f0ba..87e4a4926a5 100644
--- a/Mage.Sets/src/mage/cards/d/DecreeOfSilence.java
+++ b/Mage.Sets/src/mage/cards/d/DecreeOfSilence.java
@@ -1,14 +1,13 @@
package mage.cards.d;
-import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.CycleTriggeredAbility;
import mage.abilities.common.SpellCastOpponentTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalOneShotEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
@@ -19,33 +18,36 @@ import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.counters.CounterType;
-import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
import mage.target.TargetSpell;
+import java.util.UUID;
+
/**
- *
* @author LoneFox
*/
public final class DecreeOfSilence extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, 3);
+
public DecreeOfSilence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{6}{U}{U}");
// Whenever an opponent casts a spell, counter that spell and put a depletion counter on Decree of Silence. If there are three or more depletion counters on Decree of Silence, sacrifice it.
- Effect effect = new CounterTargetEffect();
- effect.setText("counter that spell");
- Ability ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_SPELL_A,
- false, SetTargetPointer.SPELL);
- effect = new AddCountersSourceEffect(CounterType.DEPLETION.createInstance());
- effect.setText("and put a depletion counter on {this}.");
- ability.addEffect(effect);
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(),
- new SourceHasCounterCondition(CounterType.DEPLETION, 3, Integer.MAX_VALUE),
- " If there are three or more depletion counters on {this}, sacrifice it"));
+ Ability ability = new SpellCastOpponentTriggeredAbility(
+ Zone.BATTLEFIELD, new CounterTargetEffect().setText("counter that spell"),
+ StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL
+ );
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()).concatBy("and"));
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition, "If there are " +
+ "three or more depletion counters on {this}, sacrifice it"
+ ));
this.addAbility(ability);
+
// Cycling {4}{U}{U}
this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{4}{U}{U}")));
+
// When you cycle Decree of Silence, you may counter target spell.
ability = new CycleTriggeredAbility(new CounterTargetEffect(), true);
ability.addTarget(new TargetSpell());
diff --git a/Mage.Sets/src/mage/cards/d/DeluxeDragster.java b/Mage.Sets/src/mage/cards/d/DeluxeDragster.java
index eba0ecfca95..b5100fa2b03 100644
--- a/Mage.Sets/src/mage/cards/d/DeluxeDragster.java
+++ b/Mage.Sets/src/mage/cards/d/DeluxeDragster.java
@@ -20,7 +20,7 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -54,7 +54,7 @@ public final class DeluxeDragster extends CardImpl {
+ ThatSpellGraveyardExileReplacementEffect.RULE_A);
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetCardInGraveyard(filterCard));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
// Crew 2
diff --git a/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java b/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java
index d3059c545f2..96bb4c160ac 100644
--- a/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java
+++ b/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java
@@ -20,7 +20,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate;
*/
public final class DemonicTaskmaster extends CardImpl {
- private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature other than Demonic Taskmaster");
+ private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature other than {this}");
static {
filter.add(AnotherPredicate.instance);
diff --git a/Mage.Sets/src/mage/cards/d/DiscordantSpirit.java b/Mage.Sets/src/mage/cards/d/DiscordantSpirit.java
new file mode 100644
index 00000000000..eef2f224c88
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/d/DiscordantSpirit.java
@@ -0,0 +1,118 @@
+package mage.cards.d;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.RemoveAllCountersSourceEffect;
+import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.hint.Hint;
+import mage.abilities.hint.ValueHint;
+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.constants.WatcherScope;
+import mage.counters.CounterType;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.watchers.Watcher;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class DiscordantSpirit extends CardImpl {
+
+ public DiscordantSpirit(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}");
+
+ this.subtype.add(SubType.SPIRIT);
+ this.power = new MageInt(2);
+ this.toughness = new MageInt(2);
+
+ // At the beginning of each end step, if it's an opponent's turn, put a +1/+1 counter on this creature for each 1 damage dealt to you this turn.
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.OPPONENT,
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance(), DiscordantSpiritValue.instance),
+ false
+ ).setTriggerPhrase("At the beginning of each end step, if it's an opponent's turn, ")
+ .addHint(DiscordantSpiritValue.getHint()), new DiscordantSpiritWatcher());
+
+ // At the beginning of your end step, remove all +1/+1 counters from this creature.
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.P1P1)));
+ }
+
+ private DiscordantSpirit(final DiscordantSpirit card) {
+ super(card);
+ }
+
+ @Override
+ public DiscordantSpirit copy() {
+ return new DiscordantSpirit(this);
+ }
+}
+
+enum DiscordantSpiritValue implements DynamicValue {
+ instance;
+ private static final Hint hint = new ValueHint("Damage dealt to you this turn", instance);
+
+ public static Hint getHint() {
+ return hint;
+ }
+
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ return DiscordantSpiritWatcher.getCount(game, sourceAbility);
+ }
+
+ @Override
+ public DiscordantSpiritValue copy() {
+ return this;
+ }
+
+ @Override
+ public String getMessage() {
+ return "1 damage dealt to you this turn";
+ }
+
+ @Override
+ public String toString() {
+ return "1";
+ }
+}
+
+class DiscordantSpiritWatcher extends Watcher {
+
+ private final Map map = new HashMap<>();
+
+ DiscordantSpiritWatcher() {
+ super(WatcherScope.GAME);
+ }
+
+ @Override
+ public void watch(GameEvent event, Game game) {
+ if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) {
+ map.compute(event.getTargetId(), (u, i) -> i == null ? event.getAmount() : Integer.sum(i, event.getAmount()));
+ }
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ map.clear();
+ }
+
+ static int getCount(Game game, Ability source) {
+ return game
+ .getState()
+ .getWatcher(DiscordantSpiritWatcher.class)
+ .map
+ .getOrDefault(source.getControllerId(), 0);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/d/DistendedMindbender.java b/Mage.Sets/src/mage/cards/d/DistendedMindbender.java
index 954e6261132..d12bec48bd7 100644
--- a/Mage.Sets/src/mage/cards/d/DistendedMindbender.java
+++ b/Mage.Sets/src/mage/cards/d/DistendedMindbender.java
@@ -66,7 +66,7 @@ class DistendedMindbenderEffect extends OneShotEffect {
public DistendedMindbenderEffect() {
super(Outcome.Discard);
this.staticText = "target opponent reveals their hand. " +
- "You choose from it a nonland card with mana value 3 or less and a card with mana value 4 or greater." +
+ "You choose from it a nonland card with mana value 3 or less and a card with mana value 4 or greater. " +
"That player discards those cards.";
}
diff --git a/Mage.Sets/src/mage/cards/d/DrafnaFounderOfLatNam.java b/Mage.Sets/src/mage/cards/d/DrafnaFounderOfLatNam.java
index 0468bbfe187..caa730ab411 100644
--- a/Mage.Sets/src/mage/cards/d/DrafnaFounderOfLatNam.java
+++ b/Mage.Sets/src/mage/cards/d/DrafnaFounderOfLatNam.java
@@ -16,7 +16,6 @@ import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterArtifactSpell;
import mage.target.TargetPermanent;
import mage.target.TargetSpell;
@@ -27,9 +26,10 @@ import java.util.UUID;
*/
public final class DrafnaFounderOfLatNam extends CardImpl {
- private static final FilterSpell filter = new FilterArtifactSpell("artifact spell you control");
+ private static final FilterSpell filter = new FilterSpell("artifact spell you control");
static {
+ filter.add(CardType.ARTIFACT.getPredicate());
filter.add(TargetController.YOU.getControllerPredicate());
}
diff --git a/Mage.Sets/src/mage/cards/d/DranaAndLinvala.java b/Mage.Sets/src/mage/cards/d/DranaAndLinvala.java
index 021f6aca581..bf8c376bb13 100644
--- a/Mage.Sets/src/mage/cards/d/DranaAndLinvala.java
+++ b/Mage.Sets/src/mage/cards/d/DranaAndLinvala.java
@@ -162,12 +162,10 @@ class DranaAndLinvalaManaEffect extends AsThoughEffectImpl implements AsThoughMa
return CardUtil
.getMainCardId(game, objectId)
.equals(source.getSourceId())
- && affectedAbility
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("dranaLinvalaFlag"))
- .filter(Boolean.class::isInstance)
- .anyMatch(Boolean.class::cast)
+ && CardUtil
+ .getEffectValueFromAbility(
+ affectedAbility, "dranaLinvalaFlag", Boolean.class
+ ).orElse(false)
&& source.isControlledBy(playerId);
}
diff --git a/Mage.Sets/src/mage/cards/d/DreadmawsIre.java b/Mage.Sets/src/mage/cards/d/DreadmawsIre.java
index c5703f64d9d..01c34fc336b 100644
--- a/Mage.Sets/src/mage/cards/d/DreadmawsIre.java
+++ b/Mage.Sets/src/mage/cards/d/DreadmawsIre.java
@@ -15,7 +15,7 @@ import mage.constants.CardType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetAttackingCreature;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -41,7 +41,7 @@ public final class DreadmawsIre extends CardImpl {
effect.setText("have it deal damage equal to its power to target creature that player controls.");
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(ability)
.setText("and \"Whenever this creature deals combat damage to a player, destroy target artifact that player controls.\""));
diff --git a/Mage.Sets/src/mage/cards/d/Dreamcatcher.java b/Mage.Sets/src/mage/cards/d/Dreamcatcher.java
index ac4f20ac4c6..c6c05467045 100644
--- a/Mage.Sets/src/mage/cards/d/Dreamcatcher.java
+++ b/Mage.Sets/src/mage/cards/d/Dreamcatcher.java
@@ -28,7 +28,7 @@ public final class Dreamcatcher extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, you may sacrifice Dreamcatcher. If you do, draw a card.
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(
new DrawCardSourceControllerEffect(1), new SacrificeSourceCost()
- ), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ ), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private Dreamcatcher(final Dreamcatcher card) {
diff --git a/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java b/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java
index 4904c140f5f..ec84d0ca805 100644
--- a/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java
+++ b/Mage.Sets/src/mage/cards/d/DrizztDoUrden.java
@@ -1,6 +1,7 @@
package mage.cards.d;
import mage.MageInt;
+import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@@ -19,6 +20,7 @@ import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.GuenhwyvarToken;
+import mage.util.CardUtil;
import java.util.UUID;
@@ -66,15 +68,13 @@ enum DrizztDoUrdenCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = source.getSourcePermanentOrLKI(game);
- Permanent creatureDied = (Permanent) source
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("creatureDied"))
- .findFirst()
- .orElse(null);
return sourcePermanent != null
- && creatureDied != null
- && creatureDied.getPower().getValue() > sourcePermanent.getPower().getValue();
+ && CardUtil
+ .getEffectValueFromAbility(source, "creatureDied", Permanent.class)
+ .map(MageObject::getPower)
+ .map(MageInt::getValue)
+ .filter(x -> sourcePermanent.getPower().getValue() < x)
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/e/Earthshaker.java b/Mage.Sets/src/mage/cards/e/Earthshaker.java
index f1d7f811176..059c8d14fdb 100644
--- a/Mage.Sets/src/mage/cards/e/Earthshaker.java
+++ b/Mage.Sets/src/mage/cards/e/Earthshaker.java
@@ -34,7 +34,7 @@ public final class Earthshaker extends CardImpl {
this.power = new MageInt(4);
this.toughness = new MageInt(5);
// Whenever you cast a Spirit or Arcane spell, Earthshaker deals 2 damage to each creature without flying.
- this.addAbility(new SpellCastControllerTriggeredAbility(new DamageAllEffect(StaticValue.get(2) , creatureFilter), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new DamageAllEffect(StaticValue.get(2) , creatureFilter), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private Earthshaker(final Earthshaker card) {
diff --git a/Mage.Sets/src/mage/cards/e/EdgarsAwakening.java b/Mage.Sets/src/mage/cards/e/EdgarsAwakening.java
index 5e97ea7cb09..66bf82d5c73 100644
--- a/Mage.Sets/src/mage/cards/e/EdgarsAwakening.java
+++ b/Mage.Sets/src/mage/cards/e/EdgarsAwakening.java
@@ -56,6 +56,7 @@ class EdgarsAwakeningTriggeredAbility extends TriggeredAbilityImpl {
EdgarsAwakeningTriggeredAbility() {
super(Zone.ALL, new DoWhenCostPaid(makeAbility(), new ManaCostsImpl<>("{B}"), "Pay {B}?"));
+ this.setTriggerPhrase("When you discard this card, ");
}
private EdgarsAwakeningTriggeredAbility(final EdgarsAwakeningTriggeredAbility ability) {
@@ -76,10 +77,4 @@ class EdgarsAwakeningTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkTrigger(GameEvent event, Game game) {
return this.getSourceId().equals(event.getTargetId());
}
-
- @Override
- public String getRule() {
- return "When you discard {this}, you may pay {B}. " +
- "When you do, return target creature card from your graveyard to your hand.";
- }
}
diff --git a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java
index da3725d7179..2eb546cec93 100644
--- a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java
+++ b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java
@@ -5,19 +5,19 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalActivatedAbility;
-import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.combat.CantAttackTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.Duration;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
-import mage.game.turn.Step;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
@@ -27,7 +27,7 @@ import java.util.UUID;
*/
public final class EdificeOfAuthority extends CardImpl {
- private static final String rule = "{1}, {T}: Until your next turn, target creature can't attack or block and its activated abilities can't be activated. Activate only if there are three or more brick counters on {this}.";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.BRICK, 3);
public EdificeOfAuthority(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
@@ -40,12 +40,10 @@ public final class EdificeOfAuthority extends CardImpl {
this.addAbility(ability);
// {1}, {T}: Until your next turn, target creature can't attack or block and its activated abilities can't be activated. Activate this ability only if there are three or more brick counter on Edifice of Authority.
- Condition condition = new SourceHasCounterCondition(CounterType.BRICK, 3, Integer.MAX_VALUE);
- Ability ability2 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new EdificeOfAuthorityEffect(), new ManaCostsImpl<>("{1}"), condition, rule);
+ Ability ability2 = new ConditionalActivatedAbility(new EdificeOfAuthorityEffect(), new GenericManaCost(1), condition);
ability2.addCost(new TapSourceCost());
ability2.addTarget(new TargetCreaturePermanent());
this.addAbility(ability2);
-
}
private EdificeOfAuthority(final EdificeOfAuthority card) {
@@ -58,45 +56,17 @@ public final class EdificeOfAuthority extends CardImpl {
}
}
-class EdificeOfAuthorityEffect extends OneShotEffect {
+class EdificeOfAuthorityEffect extends RestrictionEffect {
EdificeOfAuthorityEffect() {
- super(Outcome.LoseAbility);
- }
-
- public EdificeOfAuthorityEffect(String ruleText) {
- super(Outcome.LoseAbility);
- staticText = ruleText;
+ super(Duration.UntilYourNextTurn);
+ staticText = "until your next turn, target creature can't attack or block and its activated abilities can't be activated";
}
private EdificeOfAuthorityEffect(final EdificeOfAuthorityEffect effect) {
super(effect);
}
- @Override
- public EdificeOfAuthorityEffect copy() {
- return new EdificeOfAuthorityEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- EdificeOfAuthorityRestrictionEffect effect = new EdificeOfAuthorityRestrictionEffect();
- game.addEffect(effect, source);
- return true;
- }
-}
-
-class EdificeOfAuthorityRestrictionEffect extends RestrictionEffect {
-
- EdificeOfAuthorityRestrictionEffect() {
- super(Duration.Custom);
- staticText = "";
- }
-
- private EdificeOfAuthorityRestrictionEffect(final EdificeOfAuthorityRestrictionEffect effect) {
- super(effect);
- }
-
@Override
public void init(Ability source, Game game) {
super.init(source, game);
@@ -108,24 +78,6 @@ class EdificeOfAuthorityRestrictionEffect extends RestrictionEffect {
}
}
- @Override
- public boolean isInactive(Ability source, Game game) {
- if (game.getPhase().getStep().getType() == PhaseStep.UNTAP
- && game.getStep().getStepPart() == Step.StepPart.PRE) {
- if (game.isActivePlayer(source.getControllerId())
- || game.getPlayer(source.getControllerId()).hasReachedNextTurnAfterLeaving()) {
- for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
- Permanent permanent = game.getPermanent(targetId);
- if (permanent != null) {
- permanent.addInfo("Can't attack or block and its activated abilities can't be activated." + getId(), "", game);
- }
- }
- return true;
- }
- }
- return false;
- }
-
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return this.getTargetPointer().getTargets(game, source).contains(permanent.getId());
@@ -147,8 +99,8 @@ class EdificeOfAuthorityRestrictionEffect extends RestrictionEffect {
}
@Override
- public EdificeOfAuthorityRestrictionEffect copy() {
- return new EdificeOfAuthorityRestrictionEffect(this);
+ public EdificeOfAuthorityEffect copy() {
+ return new EdificeOfAuthorityEffect(this);
}
}
diff --git a/Mage.Sets/src/mage/cards/e/ElderPineOfJukai.java b/Mage.Sets/src/mage/cards/e/ElderPineOfJukai.java
index 78a76519a6c..d0186a3e41a 100644
--- a/Mage.Sets/src/mage/cards/e/ElderPineOfJukai.java
+++ b/Mage.Sets/src/mage/cards/e/ElderPineOfJukai.java
@@ -27,7 +27,7 @@ public final class ElderPineOfJukai extends CardImpl {
this.toughness = new MageInt(1);
// Whenever you cast a Spirit or Arcane spell, reveal the top three cards of your library. Put all land cards revealed this way into your hand and the rest on the bottom of your library in any order.
- this.addAbility(new SpellCastControllerTriggeredAbility(new RevealLibraryPutIntoHandEffect(3, StaticFilters.FILTER_CARD_LANDS, Zone.LIBRARY), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new RevealLibraryPutIntoHandEffect(3, StaticFilters.FILTER_CARD_LANDS, Zone.LIBRARY), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
// Soulshift 2
this.addAbility(new SoulshiftAbility(2));
diff --git a/Mage.Sets/src/mage/cards/e/ElenaTurkRecruit.java b/Mage.Sets/src/mage/cards/e/ElenaTurkRecruit.java
index c5fbea1f82f..950294a67a6 100644
--- a/Mage.Sets/src/mage/cards/e/ElenaTurkRecruit.java
+++ b/Mage.Sets/src/mage/cards/e/ElenaTurkRecruit.java
@@ -13,10 +13,9 @@ import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterCard;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricCard;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
@@ -26,10 +25,10 @@ import java.util.UUID;
*/
public final class ElenaTurkRecruit extends CardImpl {
- private static final FilterCard filter = new FilterHistoricCard("non-Assassin historic card from your graveyard");
- private static final FilterSpell filter2 = new FilterHistoricSpell();
+ private static final FilterCard filter = new FilterCard("non-Assassin historic card from your graveyard");
static {
+ filter.add(HistoricPredicate.instance);
filter.add(Predicates.not(SubType.ASSASSIN.getPredicate()));
}
@@ -49,7 +48,7 @@ public final class ElenaTurkRecruit extends CardImpl {
// Whenever you cast a historic spell, put a +1/+1 counter on Elena.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter2, false
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance()), StaticFilters.FILTER_SPELL_HISTORIC, false
));
}
diff --git a/Mage.Sets/src/mage/cards/e/ElugeTheShorelessSea.java b/Mage.Sets/src/mage/cards/e/ElugeTheShorelessSea.java
index 8b87b566f72..49005367aa2 100644
--- a/Mage.Sets/src/mage/cards/e/ElugeTheShorelessSea.java
+++ b/Mage.Sets/src/mage/cards/e/ElugeTheShorelessSea.java
@@ -118,7 +118,7 @@ class ElugeTheShorelessSeaEffect extends BecomesBasicLandTargetEffect {
ElugeTheShorelessSeaEffect() {
super(Duration.Custom, false, false, SubType.ISLAND);
- staticText = "It's an land is an Island in addition to its other types for as long as it has a flood counter on it";
+ staticText = "It's an Island in addition to its other types for as long as it has a flood counter on it";
}
private ElugeTheShorelessSeaEffect(final ElugeTheShorelessSeaEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/e/EshkiTemursRoar.java b/Mage.Sets/src/mage/cards/e/EshkiTemursRoar.java
index 2e8c907d1ef..ca711ba0931 100644
--- a/Mage.Sets/src/mage/cards/e/EshkiTemursRoar.java
+++ b/Mage.Sets/src/mage/cards/e/EshkiTemursRoar.java
@@ -75,15 +75,11 @@ enum EshkiTemursRoarCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
- return CardUtil.castStream(
- source.getEffects()
- .stream()
- .map(effect -> effect.getValue("spellCast")),
- Spell.class
- )
- .findFirst()
+ return CardUtil
+ .getEffectValueFromAbility(source, "spellCast", Spell.class)
.map(Spell::getPower)
.map(MageInt::getValue)
- .orElse(0) >= amount;
+ .filter(x -> x >= amount)
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java
index 849f43f2213..58f5cad072c 100644
--- a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java
+++ b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java
@@ -18,7 +18,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -44,7 +44,7 @@ public final class EtrataTheSilencer extends CardImpl {
// Whenever Etrata deals combat damage to a player, exile target creature that player controls and put a hit counter on that card. That player loses the game if they own three or more exiled card with hit counters on them. Etrata's owner shuffles Etrata into their library.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new EtrataTheSilencerEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/e/EverybodyLives.java b/Mage.Sets/src/mage/cards/e/EverybodyLives.java
new file mode 100644
index 00000000000..f719f9fb6b6
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/e/EverybodyLives.java
@@ -0,0 +1,108 @@
+package mage.cards.e;
+
+import mage.abilities.Ability;
+import mage.abilities.effects.ContinuousEffectImpl;
+import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
+import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
+import mage.abilities.keyword.HexproofAbility;
+import mage.abilities.keyword.IndestructibleAbility;
+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.players.Player;
+
+import java.util.UUID;
+
+/**
+ * @author padfoot
+ */
+public final class EverybodyLives extends CardImpl {
+
+ public EverybodyLives(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
+
+ // All creatures gain hexproof and indestructible until end of turn.
+ this.getSpellAbility().addEffect(new GainAbilityAllEffect(
+ HexproofAbility.getInstance(),
+ Duration.EndOfTurn,
+ StaticFilters.FILTER_PERMANENT_ALL_CREATURES
+ ).setText("all creatures gain hexproof"));
+ this.getSpellAbility().addEffect(new GainAbilityAllEffect(
+ IndestructibleAbility.getInstance(),
+ Duration.EndOfTurn,
+ StaticFilters.FILTER_PERMANENT_ALL_CREATURES
+ ).setText("and indestructible until end of turn"));
+
+ // Players gain hexproof until end of turn. Players can't lose life this turn and players can't lose the game or win the game this turn.
+ this.getSpellAbility().addEffect(new EverybodyLivesPlayerEffect());
+ this.getSpellAbility().addEffect(new EverybodyLivesCantLoseOrWinGameEffect());
+ }
+
+ private EverybodyLives(final EverybodyLives card) {
+ super(card);
+ }
+
+ @Override
+ public EverybodyLives copy() {
+ return new EverybodyLives(this);
+ }
+}
+
+class EverybodyLivesPlayerEffect extends ContinuousEffectImpl {
+
+ EverybodyLivesPlayerEffect() {
+ super(Duration.EndOfTurn, Layer.PlayerEffects, SubLayer.NA, Outcome.AddAbility);
+ this.staticText = "Players gain hexproof until end of turn. Players can't lose life this turn";
+ }
+
+ private EverybodyLivesPlayerEffect(final EverybodyLivesPlayerEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public EverybodyLivesPlayerEffect copy() {
+ return new EverybodyLivesPlayerEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
+ Player player = game.getPlayer(playerId);
+ if (player != null) {
+ player.addAbility(HexproofAbility.getInstance());
+ player.setCanLoseLife(false);
+ }
+ }
+ return true;
+ }
+}
+
+class EverybodyLivesCantLoseOrWinGameEffect extends ContinuousRuleModifyingEffectImpl {
+
+ EverybodyLivesCantLoseOrWinGameEffect() {
+ super(Duration.EndOfTurn, Outcome.Benefit, false, false);
+ staticText = "and players can't lose the game or win the game this turn";
+ }
+
+ private EverybodyLivesCantLoseOrWinGameEffect(final EverybodyLivesCantLoseOrWinGameEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public EverybodyLivesCantLoseOrWinGameEffect copy() {
+ return new EverybodyLivesCantLoseOrWinGameEffect(this);
+ }
+
+ @Override
+ public boolean checksEventType(GameEvent event, Game game) {
+ return (event.getType() == GameEvent.EventType.LOSES || event.getType() == GameEvent.EventType.WINS);
+ }
+
+ @Override
+ public boolean applies(GameEvent event, Ability source, Game game) {
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/e/EvolvedSpinoderm.java b/Mage.Sets/src/mage/cards/e/EvolvedSpinoderm.java
index 0403b2d3f31..8d9789f0196 100644
--- a/Mage.Sets/src/mage/cards/e/EvolvedSpinoderm.java
+++ b/Mage.Sets/src/mage/cards/e/EvolvedSpinoderm.java
@@ -2,7 +2,6 @@ package mage.cards.e;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
@@ -15,9 +14,11 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.HexproofAbility;
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.ComparisonType;
import mage.constants.SubType;
import mage.counters.CounterType;
@@ -28,8 +29,8 @@ import java.util.UUID;
*/
public final class EvolvedSpinoderm extends CardImpl {
- private static final Condition condition1 = new SourceHasCounterCondition(CounterType.OIL, 3);
- private static final Condition condition2 = new SourceHasCounterCondition(CounterType.OIL, 0, 0);
+ private static final Condition condition1 = new SourceHasCounterCondition(CounterType.OIL, ComparisonType.OR_LESS, 2);
+ private static final Condition condition2 = new SourceHasCounterCondition(CounterType.OIL, ComparisonType.EQUAL_TO, 0);
public EvolvedSpinoderm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}");
diff --git a/Mage.Sets/src/mage/cards/e/ExperimentOne.java b/Mage.Sets/src/mage/cards/e/ExperimentOne.java
index dd3989f1704..b262f1def2a 100644
--- a/Mage.Sets/src/mage/cards/e/ExperimentOne.java
+++ b/Mage.Sets/src/mage/cards/e/ExperimentOne.java
@@ -1,6 +1,5 @@
package mage.cards.e;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost;
@@ -10,11 +9,11 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class ExperimentOne extends CardImpl {
@@ -32,7 +31,7 @@ public final class ExperimentOne extends CardImpl {
this.addAbility(new EvolveAbility());
//Remove two +1/+1 counters from Experiment One: Regenerate Experiment One.
- this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new RemoveCountersSourceCost(CounterType.P1P1.createInstance(2))));
+ this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect("it"), new RemoveCountersSourceCost(CounterType.P1P1.createInstance(2))));
}
private ExperimentOne(final ExperimentOne card) {
diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveGetaway.java b/Mage.Sets/src/mage/cards/e/ExplosiveGetaway.java
index 5410a4bcbc1..4f2f182a89c 100644
--- a/Mage.Sets/src/mage/cards/e/ExplosiveGetaway.java
+++ b/Mage.Sets/src/mage/cards/e/ExplosiveGetaway.java
@@ -1,43 +1,29 @@
package mage.cards.e;
-import java.util.UUID;
-import java.util.function.Predicate;
-
-import mage.abilities.Ability;
-import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.ExileReturnBattlefieldNextEndStepTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
-import mage.filter.predicate.Predicates;
import mage.target.TargetPermanent;
+import java.util.UUID;
+
/**
- *
* @author Jmlundeen
*/
public final class ExplosiveGetaway extends CardImpl {
- private static final FilterPermanent filter = new FilterPermanent("artifact or creature");
-
- static {
- filter.add(Predicates.or(
- CardType.ARTIFACT.getPredicate(),
- CardType.CREATURE.getPredicate()
- ));
- }
public ExplosiveGetaway(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{W}");
-
// Exile up to one target artifact or creature. Return it to the battlefield under its owner's control at the beginning of the next end step.
this.getSpellAbility().addEffect(new ExileReturnBattlefieldNextEndStepTargetEffect().withTextThatCard(false));
- this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter));
+ this.getSpellAbility().addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE));
+
// Explosive Getaway deals 4 damage to each creature.
- this.getSpellAbility().addEffect(new DamageAllEffect(4, StaticFilters.FILTER_PERMANENT_ALL_CREATURES).concatBy("
"));
+ this.getSpellAbility().addEffect(new DamageAllEffect(4, StaticFilters.FILTER_PERMANENT_CREATURE).concatBy("
"));
}
private ExplosiveGetaway(final ExplosiveGetaway card) {
diff --git a/Mage.Sets/src/mage/cards/f/FabledPassage.java b/Mage.Sets/src/mage/cards/f/FabledPassage.java
index ce6a2c90e8f..5301cd4bc35 100644
--- a/Mage.Sets/src/mage/cards/f/FabledPassage.java
+++ b/Mage.Sets/src/mage/cards/f/FabledPassage.java
@@ -16,9 +16,7 @@ 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.TargetCardInLibrary;
-import mage.target.targetpointer.FirstTargetPointer;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
@@ -53,7 +51,7 @@ class FabledPassageSearchForLandEffect extends OneShotEffect {
FabledPassageSearchForLandEffect() {
super(Outcome.PutCardInPlay);
- staticText = "Search your library for a basic land card, put it onto the battlefield tapped, then shuffle ";
+ staticText = "Search your library for a basic land card, put it onto the battlefield tapped, then shuffle";
}
private FabledPassageSearchForLandEffect(final FabledPassageSearchForLandEffect effect) {
@@ -129,4 +127,4 @@ class FabledPassageUntapLandEffect extends OneShotEffect {
public FabledPassageUntapLandEffect copy() {
return new FabledPassageUntapLandEffect(this);
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java
index cbda9137108..0098ae14971 100644
--- a/Mage.Sets/src/mage/cards/f/FaithboundJudge.java
+++ b/Mage.Sets/src/mage/cards/f/FaithboundJudge.java
@@ -1,21 +1,21 @@
package mage.cards.f;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalAsThoughEffect;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
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.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.counters.CounterType;
@@ -27,7 +27,7 @@ import java.util.UUID;
*/
public final class FaithboundJudge extends CardImpl {
- private static final Condition condition1 = new SourceHasCounterCondition(CounterType.JUDGMENT, 0, 2);
+ 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) {
@@ -49,18 +49,16 @@ public final class FaithboundJudge extends CardImpl {
this.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 ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(
- new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance()), false
- ), condition1, "At the beginning of your upkeep, if {this} has " +
- "two or fewer judgment counters on it, put a judgment counter on it."
- ));
+ this.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(
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")));
+ ).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}"));
diff --git a/Mage.Sets/src/mage/cards/f/FaithfulPikemaster.java b/Mage.Sets/src/mage/cards/f/FaithfulPikemaster.java
index a990fe5b854..7ec554a3515 100644
--- a/Mage.Sets/src/mage/cards/f/FaithfulPikemaster.java
+++ b/Mage.Sets/src/mage/cards/f/FaithfulPikemaster.java
@@ -37,7 +37,7 @@ public final class FaithfulPikemaster extends CardImpl {
// As long as it's your turn, Faithful Pikemaster has first strike.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield),
- MyTurnCondition.instance, "during your turn, {this} has first strike."
+ MyTurnCondition.instance, "as long as it's your turn, {this} has first strike."
)).addHint(MyTurnHint.instance));
}
diff --git a/Mage.Sets/src/mage/cards/f/FaithfulSquire.java b/Mage.Sets/src/mage/cards/f/FaithfulSquire.java
index 4bdc2d2c819..afdf306f44c 100644
--- a/Mage.Sets/src/mage/cards/f/FaithfulSquire.java
+++ b/Mage.Sets/src/mage/cards/f/FaithfulSquire.java
@@ -1,36 +1,34 @@
package mage.cards.f;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.common.PreventDamageToTargetEffect;
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.constants.Duration;
-import mage.constants.SuperType;
-import mage.constants.Zone;
+import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
import mage.target.common.TargetCreaturePermanent;
+import java.util.UUID;
+
/**
* @author LevelX2
*/
public final class FaithfulSquire extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.KI, 2);
+
public FaithfulSquire(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}");
this.subtype.add(SubType.HUMAN);
@@ -42,14 +40,15 @@ public final class FaithfulSquire extends CardImpl {
this.flipCardName = "Kaiso, Memory of Loyalty";
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Faithful Squire.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.KI.createInstance()),
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true
+ ));
// At the beginning of the end step, if there are two or more ki counters on Faithful Squire, you may flip it
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new KaisoMemoryOfLoyaltyToken()), true),
- new SourceHasCounterCondition(CounterType.KI, 2, Integer.MAX_VALUE),
- "At the beginning of the end step, if there are two or more ki counters on {this}, you may flip it."));
-
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.NEXT, new FlipSourceEffect(new KaisoMemoryOfLoyaltyToken()).setText("flip it"), true, condition
+ ));
}
private FaithfulSquire(final FaithfulSquire card) {
diff --git a/Mage.Sets/src/mage/cards/f/FaridehDevilsChosen.java b/Mage.Sets/src/mage/cards/f/FaridehDevilsChosen.java
index f9ff066ec65..73642c06f44 100644
--- a/Mage.Sets/src/mage/cards/f/FaridehDevilsChosen.java
+++ b/Mage.Sets/src/mage/cards/f/FaridehDevilsChosen.java
@@ -16,8 +16,8 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.game.Game;
+import mage.util.CardUtil;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -65,12 +65,9 @@ enum FaridehDevilsChosenCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
- return source
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("maxDieRoll"))
- .filter(Objects::nonNull)
- .mapToInt(Integer.class::cast)
- .anyMatch(x -> x >= 10);
+ return CardUtil
+ .getEffectValueFromAbility(source, "maxDieRoll", Integer.class)
+ .filter(x -> x >= 10)
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/f/FearOfSleepParalysis.java b/Mage.Sets/src/mage/cards/f/FearOfSleepParalysis.java
index db977eb225d..eab4edbe21d 100644
--- a/Mage.Sets/src/mage/cards/f/FearOfSleepParalysis.java
+++ b/Mage.Sets/src/mage/cards/f/FearOfSleepParalysis.java
@@ -38,7 +38,7 @@ public final class FearOfSleepParalysis extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// 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.
- Ability ability = new EerieAbility(new TapTargetEffect());
+ Ability ability = new EerieAbility(new TapTargetEffect()).setTriggerPhrase("Whenever this creature or another enchantment you control enters and whenever you fully unlock a Room, ");
ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()).setText("and put a stun counter on it"));
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability);
@@ -89,4 +89,4 @@ class FearOfSleepParalysisEffect extends ReplacementEffectImpl {
return target != null && event.getData().equals(CounterType.STUN.getName()) && !target.getControllerId().equals(source.getControllerId());
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/f/FecundGreenshell.java b/Mage.Sets/src/mage/cards/f/FecundGreenshell.java
index 3a88f596fd6..78362c58dd3 100644
--- a/Mage.Sets/src/mage/cards/f/FecundGreenshell.java
+++ b/Mage.Sets/src/mage/cards/f/FecundGreenshell.java
@@ -1,7 +1,5 @@
package mage.cards.f;
-import java.util.UUID;
-
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
@@ -11,24 +9,27 @@ import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.hint.common.LandsYouControlHint;
-import mage.cards.Card;
-import mage.constants.*;
import mage.abilities.keyword.ReachAbility;
+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.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.ToughnessGreaterThanPowerPredicate;
import mage.game.Game;
import mage.players.Player;
+import java.util.UUID;
+
/**
* @author Cguy7777
*/
public final class FecundGreenshell extends CardImpl {
- private static final FilterCreaturePermanent filter
- = new FilterCreaturePermanent("creature you control with toughness greater than its power");
+ private static final FilterPermanent filter
+ = new FilterControlledCreaturePermanent("creature you control with toughness greater than its power");
static {
filter.add(ToughnessGreaterThanPowerPredicate.instance);
@@ -59,7 +60,7 @@ public final class FecundGreenshell extends CardImpl {
// Whenever Fecund Greenshell or another creature you control with toughness greater than its power enters,
// look at the top card of your library. If it's a land card, you may put it onto the battlefield tapped. Otherwise, put it into your hand.
this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(
- new FecundGreenshellEffect(), filter, false, true));
+ new FecundGreenshellEffect(), filter, false, false));
}
private FecundGreenshell(final FecundGreenshell card) {
diff --git a/Mage.Sets/src/mage/cards/f/FiddleheadKami.java b/Mage.Sets/src/mage/cards/f/FiddleheadKami.java
index 6017d582d04..3e843e39d52 100644
--- a/Mage.Sets/src/mage/cards/f/FiddleheadKami.java
+++ b/Mage.Sets/src/mage/cards/f/FiddleheadKami.java
@@ -25,7 +25,7 @@ public final class FiddleheadKami extends CardImpl {
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, regenerate Fiddlehead Kami.
- this.addAbility(new SpellCastControllerTriggeredAbility(new RegenerateSourceEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new RegenerateSourceEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private FiddleheadKami(final FiddleheadKami card) {
diff --git a/Mage.Sets/src/mage/cards/f/ForTheCommonGood.java b/Mage.Sets/src/mage/cards/f/ForTheCommonGood.java
index 1d90d44e6ad..ac25c6345e0 100644
--- a/Mage.Sets/src/mage/cards/f/ForTheCommonGood.java
+++ b/Mage.Sets/src/mage/cards/f/ForTheCommonGood.java
@@ -50,7 +50,7 @@ public final class ForTheCommonGood extends CardImpl {
IndestructibleAbility.getInstance(),
Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_TOKENS
).concatBy("Then"));
- this.getSpellAbility().addEffect(new GainLifeEffect(xValue));
+ this.getSpellAbility().addEffect(new GainLifeEffect(xValue).setText("You gain 1 life for each token you control"));
this.getSpellAbility().addHint(hint);
}
diff --git a/Mage.Sets/src/mage/cards/f/FuriousSpinesplitter.java b/Mage.Sets/src/mage/cards/f/FuriousSpinesplitter.java
new file mode 100644
index 00000000000..bfae9505ed1
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/f/FuriousSpinesplitter.java
@@ -0,0 +1,82 @@
+package mage.cards.f;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.keyword.TrampleAbility;
+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 mage.game.Game;
+import mage.watchers.common.AmountOfDamageAPlayerReceivedThisTurnWatcher;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class FuriousSpinesplitter extends CardImpl {
+
+ public FuriousSpinesplitter(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/G}{R/G}");
+
+ this.subtype.add(SubType.OGRE);
+ this.subtype.add(SubType.WARRIOR);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(3);
+
+ // Trample
+ this.addAbility(TrampleAbility.getInstance());
+
+ // At the beginning of your end step, put a +1/+1 counter on Furious Spinesplitter for each opponent that was dealt damage this turn.
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(
+ CounterType.P1P1.createInstance(), FuriousSpinesplitterValue.instance
+ )), new AmountOfDamageAPlayerReceivedThisTurnWatcher());
+ }
+
+ private FuriousSpinesplitter(final FuriousSpinesplitter card) {
+ super(card);
+ }
+
+ @Override
+ public FuriousSpinesplitter copy() {
+ return new FuriousSpinesplitter(this);
+ }
+}
+
+enum FuriousSpinesplitterValue implements DynamicValue {
+ instance;
+
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ return game
+ .getOpponents(sourceAbility.getControllerId())
+ .stream()
+ .map(game
+ .getState()
+ .getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class)
+ ::getAmountOfDamageReceivedThisTurn)
+ .mapToInt(x -> Math.min(x, 1))
+ .sum();
+ }
+
+ @Override
+ public FuriousSpinesplitterValue copy() {
+ return this;
+ }
+
+ @Override
+ public String getMessage() {
+ return "opponent that was dealt damage this turn";
+ }
+
+ @Override
+ public String toString() {
+ return "1";
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/g/GarruksUprising.java b/Mage.Sets/src/mage/cards/g/GarruksUprising.java
index 180629f5d1f..98af2de7350 100644
--- a/Mage.Sets/src/mage/cards/g/GarruksUprising.java
+++ b/Mage.Sets/src/mage/cards/g/GarruksUprising.java
@@ -1,10 +1,9 @@
package mage.cards.g;
-import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
+import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.FerociousCondition;
-import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.hint.common.FerociousHint;
@@ -17,18 +16,17 @@ import mage.constants.Duration;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
import java.util.UUID;
/**
- *
* @author htrajan
*/
public final class GarruksUprising extends CardImpl {
- private static final FilterPermanent filter = new FilterCreaturePermanent("a creature with power 4 or greater");
+ private static final FilterPermanent filter = new FilterControlledCreaturePermanent("a creature you control with power 4 or greater");
static {
filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3));
@@ -38,9 +36,9 @@ public final class GarruksUprising extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
// When Garruk's Uprising enters the battlefield, if you control a creature with power 4 or greater, draw a card.
- this.addAbility(new EntersBattlefieldTriggeredAbility(new ConditionalOneShotEffect(
- new DrawCardSourceControllerEffect(1), FerociousCondition.instance))
- .addHint(FerociousHint.instance));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))
+ .withInterveningIf(FerociousCondition.instance)
+ .addHint(FerociousHint.instance));
// Creatures you control have trample.
this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
@@ -49,7 +47,7 @@ public final class GarruksUprising extends CardImpl {
)));
// Whenever a creature with power 4 or greater you control enters, draw a card.
- this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
+ this.addAbility(new EntersBattlefieldAllTriggeredAbility(
Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, false
));
}
diff --git a/Mage.Sets/src/mage/cards/g/GemstoneMine.java b/Mage.Sets/src/mage/cards/g/GemstoneMine.java
index 50c2aa87f78..16f1407978d 100644
--- a/Mage.Sets/src/mage/cards/g/GemstoneMine.java
+++ b/Mage.Sets/src/mage/cards/g/GemstoneMine.java
@@ -1,9 +1,9 @@
package mage.cards.g;
-import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.decorator.ConditionalOneShotEffect;
@@ -13,16 +13,20 @@ import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author jeffwadsworth
*/
public final class GemstoneMine extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.MINING, ComparisonType.EQUAL_TO, 0);
+
public GemstoneMine(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Gemstone Mine enters the battlefield with three mining counters on it.
this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.MINING.createInstance(3)),
@@ -31,7 +35,10 @@ public final class GemstoneMine extends CardImpl {
// {T}, Remove a mining counter from Gemstone Mine: Add one mana of any color. If there are no mining counters on Gemstone Mine, sacrifice it.
Ability ability = new AnyColorManaAbility();
ability.addCost(new RemoveCountersSourceCost(CounterType.MINING.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.MINING, 0, 0), "If there are no mining counters on {this}, sacrifice it"));
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no mining counters on {this}, sacrifice it"
+ ));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/g/GloinDwarfEmissary.java b/Mage.Sets/src/mage/cards/g/GloinDwarfEmissary.java
index a305271e9a5..f8124235f41 100644
--- a/Mage.Sets/src/mage/cards/g/GloinDwarfEmissary.java
+++ b/Mage.Sets/src/mage/cards/g/GloinDwarfEmissary.java
@@ -13,9 +13,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.FilterSpell;
+import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
-import mage.filter.common.FilterHistoricSpell;
import mage.game.permanent.token.TreasureToken;
import mage.target.common.TargetCreaturePermanent;
@@ -26,7 +25,6 @@ import java.util.UUID;
*/
public final class GloinDwarfEmissary extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
private static final FilterControlledPermanent filter2 = new FilterControlledPermanent(SubType.TREASURE, "a Treasure");
public GloinDwarfEmissary(UUID ownerId, CardSetInfo setInfo) {
@@ -40,7 +38,7 @@ public final class GloinDwarfEmissary extends CardImpl {
// Whenever you cast a historic spell, create a Treasure token. This ability triggers only once each turn.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new CreateTokenEffect(new TreasureToken()), filter, false
+ new CreateTokenEffect(new TreasureToken()), StaticFilters.FILTER_SPELL_HISTORIC, false
).setTriggersLimitEachTurn(1));
// {T}, Sacrifice a Treasure: Goad target creature.
diff --git a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java
index e9f7d247e3a..d134b26b94b 100644
--- a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java
+++ b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java
@@ -14,7 +14,6 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterSpell;
-import mage.filter.common.FilterArtifactSpell;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
@@ -58,17 +57,18 @@ public final class GoblinArtisans extends CardImpl {
class GoblinArtisansTarget extends TargetSpell {
- private static final FilterSpell filter = new FilterArtifactSpell(
+ private static final FilterSpell filterSpell = new FilterSpell(
"target artifact spell you control that isn't the target " +
"of an ability from another creature named Goblin Artisans"
);
static {
- filter.add(TargetController.YOU.getOwnerPredicate());
+ filterSpell.add(CardType.ARTIFACT.getPredicate());
+ filterSpell.add(TargetController.YOU.getOwnerPredicate());
}
GoblinArtisansTarget() {
- super(filter);
+ super(filterSpell);
}
private GoblinArtisansTarget(final GoblinArtisansTarget target) {
diff --git a/Mage.Sets/src/mage/cards/g/Godsend.java b/Mage.Sets/src/mage/cards/g/Godsend.java
index 7f07da8d55c..ccf9d841a03 100644
--- a/Mage.Sets/src/mage/cards/g/Godsend.java
+++ b/Mage.Sets/src/mage/cards/g/Godsend.java
@@ -167,7 +167,7 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl {
GodsendRuleModifyingEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
- staticText = "Your opponents can't cast cards with the same name as cards exiled with {this}";
+ staticText = "Your opponents can't cast spells with the same name as a card exiled with {this}";
}
private GodsendRuleModifyingEffect(final GodsendRuleModifyingEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/g/GossipsTalent.java b/Mage.Sets/src/mage/cards/g/GossipsTalent.java
index e160bd5e9f7..d347e6b334a 100644
--- a/Mage.Sets/src/mage/cards/g/GossipsTalent.java
+++ b/Mage.Sets/src/mage/cards/g/GossipsTalent.java
@@ -1,7 +1,10 @@
package mage.cards.g;
import mage.abilities.Ability;
-import mage.abilities.common.*;
+import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
+import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
+import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
+import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.ExileThenReturnTargetEffect;
import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect;
import mage.abilities.effects.common.continuous.GainClassAbilitySourceEffect;
@@ -10,7 +13,10 @@ import mage.abilities.keyword.ClassLevelAbility;
import mage.abilities.keyword.ClassReminderAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.constants.SetTargetPointer;
+import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterAttackingCreature;
@@ -24,7 +30,7 @@ import java.util.UUID;
*/
public final class GossipsTalent extends CardImpl {
- private static final FilterPermanent filter = new FilterAttackingCreature("attacking creature with power 3 or less can't be blocked this turn");
+ private static final FilterPermanent filter = new FilterAttackingCreature("attacking creature with power 3 or less");
static {
filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 4));
@@ -59,7 +65,7 @@ public final class GossipsTalent extends CardImpl {
new DealsDamageToAPlayerAllTriggeredAbility(
new ExileThenReturnTargetEffect(false, false)
.setText("exile it, then return it to the battlefield under its owner's control"),
- StaticFilters.FILTER_PERMANENT_CREATURE, true, SetTargetPointer.PERMANENT, true
+ StaticFilters.FILTER_CONTROLLED_CREATURE, true, SetTargetPointer.PERMANENT, true
), 3
)));
}
diff --git a/Mage.Sets/src/mage/cards/g/GryffsBoon.java b/Mage.Sets/src/mage/cards/g/GryffsBoon.java
index 5f56a7ade08..213309ba88c 100644
--- a/Mage.Sets/src/mage/cards/g/GryffsBoon.java
+++ b/Mage.Sets/src/mage/cards/g/GryffsBoon.java
@@ -66,7 +66,7 @@ class GryffsBoonEffect extends OneShotEffect {
GryffsBoonEffect() {
super(Outcome.PutCardInPlay);
- staticText = "Return {this} from your graveyard to the battlefield attached to target creature";
+ staticText = "Return this card from your graveyard to the battlefield attached to target creature";
}
private GryffsBoonEffect(final GryffsBoonEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfSolitude.java b/Mage.Sets/src/mage/cards/g/GuardianOfSolitude.java
index 0782d6fa957..f05935cace1 100644
--- a/Mage.Sets/src/mage/cards/g/GuardianOfSolitude.java
+++ b/Mage.Sets/src/mage/cards/g/GuardianOfSolitude.java
@@ -27,7 +27,7 @@ public final class GuardianOfSolitude extends CardImpl {
this.power = new MageInt(1);
this.toughness = new MageInt(2);
- Ability ability = new SpellCastControllerTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/g/GuidelightOptimizer.java b/Mage.Sets/src/mage/cards/g/GuidelightOptimizer.java
index 344860c6e58..3d9d9504de3 100644
--- a/Mage.Sets/src/mage/cards/g/GuidelightOptimizer.java
+++ b/Mage.Sets/src/mage/cards/g/GuidelightOptimizer.java
@@ -53,7 +53,7 @@ class ArtifactOrActivatedManaBuilder extends ConditionalManaBuilder {
@Override
public String getRule() {
- return "Spend this mana only to cast an artifact spells or activate an ability";
+ return "Spend this mana only to cast an artifact spell or activate an ability";
}
}
@@ -61,7 +61,7 @@ class ArtifactOrActivatedConditionalMana extends ConditionalMana {
public ArtifactOrActivatedConditionalMana(Mana mana) {
super(mana);
- staticText = "Spend this mana only to cast an artifact spells or activate an ability";
+ staticText = "Spend this mana only to cast an artifact spell or activate an ability";
addCondition(new ArtifactOrActivatedManaCondition());
}
}
@@ -80,4 +80,4 @@ class ArtifactOrActivatedManaCondition extends ManaCondition implements Conditio
public boolean apply(Game game, Ability source, UUID originalId, mage.abilities.costs.Cost costsToPay) {
return apply(game, source);
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/h/HaltOrder.java b/Mage.Sets/src/mage/cards/h/HaltOrder.java
index 9152886692a..51c9a15d69c 100644
--- a/Mage.Sets/src/mage/cards/h/HaltOrder.java
+++ b/Mage.Sets/src/mage/cards/h/HaltOrder.java
@@ -1,25 +1,31 @@
-
package mage.cards.h;
-import java.util.UUID;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.filter.common.FilterArtifactSpell;
+import mage.filter.FilterSpell;
import mage.target.TargetSpell;
+import java.util.UUID;
+
/**
*
* @author Loki
*/
public final class HaltOrder extends CardImpl {
+
+ private static final FilterSpell filter = new FilterSpell("artifact spell");
+ static {
+ filter.add(CardType.ARTIFACT.getPredicate());
+ }
+
public HaltOrder (UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}");
// Counter target artifact spell. Draw a card.
- this.getSpellAbility().addTarget(new TargetSpell(new FilterArtifactSpell()));
+ this.getSpellAbility().addTarget(new TargetSpell(filter));
this.getSpellAbility().addEffect(new CounterTargetEffect());
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
"));
}
diff --git a/Mage.Sets/src/mage/cards/h/HammerOfRuin.java b/Mage.Sets/src/mage/cards/h/HammerOfRuin.java
index 85331db5be1..9ceb1aecafc 100644
--- a/Mage.Sets/src/mage/cards/h/HammerOfRuin.java
+++ b/Mage.Sets/src/mage/cards/h/HammerOfRuin.java
@@ -16,7 +16,7 @@ import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -38,7 +38,7 @@ public final class HammerOfRuin extends CardImpl {
// Whenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls.
Ability ability = new DealsDamageToAPlayerAttachedTriggeredAbility(new DestroyTargetEffect(), "equipped creature", true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
// Equip {2}
diff --git a/Mage.Sets/src/mage/cards/h/HammerheadTyrant.java b/Mage.Sets/src/mage/cards/h/HammerheadTyrant.java
index 0e10903c3a9..eab93495e3e 100644
--- a/Mage.Sets/src/mage/cards/h/HammerheadTyrant.java
+++ b/Mage.Sets/src/mage/cards/h/HammerheadTyrant.java
@@ -70,19 +70,10 @@ enum HammerheadTyrantPredicate implements ObjectSourcePlayerPredicate
@Override
public boolean apply(ObjectSourcePlayer input, Game game) {
- return input
- .getObject()
- .getManaValue()
- <= CardUtil
- .castStream(
- input.getSource()
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("spellCast")),
- Spell.class
- )
- .findFirst()
+ return CardUtil
+ .getEffectValueFromAbility(input.getSource(), "spellCast", Spell.class)
.map(Spell::getManaValue)
- .orElse(-1);
+ .filter(x -> x >= input.getObject().getManaValue())
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/h/HareApparent.java b/Mage.Sets/src/mage/cards/h/HareApparent.java
index ef347f862e8..151733fc391 100644
--- a/Mage.Sets/src/mage/cards/h/HareApparent.java
+++ b/Mage.Sets/src/mage/cards/h/HareApparent.java
@@ -47,6 +47,8 @@ public final class HareApparent extends CardImpl {
// When this creature enters, create a number of 1/1 white Rabbit creature tokens equal to the number of other creatures you control named Hare Apparent.
this.addAbility(new EntersBattlefieldTriggeredAbility(
new CreateTokenEffect(new RabbitToken(), xValue)
+ .setText("create a number of 1/1 white Rabbit creature tokens equal " +
+ "to the number of other creatures you control named Hare Apparent")
).addHint(hint));
// A deck can have any number of cards named Hare Apparent.
diff --git a/Mage.Sets/src/mage/cards/h/HaruOnna.java b/Mage.Sets/src/mage/cards/h/HaruOnna.java
index 718971ba425..3c8c988759e 100644
--- a/Mage.Sets/src/mage/cards/h/HaruOnna.java
+++ b/Mage.Sets/src/mage/cards/h/HaruOnna.java
@@ -29,7 +29,7 @@ public final class HaruOnna extends CardImpl {
// When Haru-Onna enters the battlefield, draw a card.
this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)));
// Whenever you cast a Spirit or Arcane spell, you may return Haru-Onna to its owner's hand.
- this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private HaruOnna(final HaruOnna card) {
diff --git a/Mage.Sets/src/mage/cards/h/HashatonScarabsFist.java b/Mage.Sets/src/mage/cards/h/HashatonScarabsFist.java
index 0423996ec28..135de070b3a 100644
--- a/Mage.Sets/src/mage/cards/h/HashatonScarabsFist.java
+++ b/Mage.Sets/src/mage/cards/h/HashatonScarabsFist.java
@@ -83,7 +83,7 @@ class HashatonScarabsFistEffect extends OneShotEffect {
HashatonScarabsFistEffect() {
super(Outcome.PutCreatureInPlay);
- this.staticText = "create a tapped token that`s a copy of that card, except it`s a 4/4 black Zombie";
+ this.staticText = "create a tapped token that's a copy of that card, except it's a 4/4 black Zombie";
}
private HashatonScarabsFistEffect(OneShotEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/h/HauntedScreen.java b/Mage.Sets/src/mage/cards/h/HauntedScreen.java
index 773a04ee2f7..24bb9b85055 100644
--- a/Mage.Sets/src/mage/cards/h/HauntedScreen.java
+++ b/Mage.Sets/src/mage/cards/h/HauntedScreen.java
@@ -46,7 +46,8 @@ public final class HauntedScreen extends CardImpl {
);
ability.addEffect(new BecomesCreatureSourceEffect(new CreatureToken(
0, 0, "0/0 Spirit creature", SubType.SPIRIT
- ), CardType.ARTIFACT, Duration.Custom).withKeepCreatureSubtypes(true));
+ ), CardType.ARTIFACT, Duration.Custom).withKeepCreatureSubtypes(true)
+ .setText("It becomes a 0/0 Spirit creature in addition to its other types"));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java b/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java
index e79e460bb93..f5d28e0b4d2 100644
--- a/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java
+++ b/Mage.Sets/src/mage/cards/h/HaviTheAllFather.java
@@ -23,9 +23,9 @@ import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
-import mage.filter.common.FilterHistoricCard;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
@@ -38,19 +38,20 @@ import java.util.UUID;
*/
public final class HaviTheAllFather extends CardImpl {
- private static final Condition condition = new CardsInControllerGraveyardCondition(
- 4, new FilterHistoricCard("historic cards")
- );
- private static final Hint hint = new ValueHint(
- "Historic cards in your graveyard", new CardsInControllerGraveyardCount(new FilterHistoricCard())
- );
+ private static final FilterCard filterHistoric = new FilterCard("historic cards");
private static final FilterCard filter = new FilterCreatureCard("legendary creature card with lesser mana value from your graveyard");
static {
+ filterHistoric.add(HistoricPredicate.instance);
filter.add(SuperType.LEGENDARY.getPredicate());
filter.add(HaviTheAllFatherPredicate.instance);
}
+ private static final Condition condition = new CardsInControllerGraveyardCondition(4, filterHistoric);
+ private static final Hint hint = new ValueHint(
+ "Historic cards in your graveyard", new CardsInControllerGraveyardCount(filterHistoric)
+ );
+
public HaviTheAllFather(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{W}");
diff --git a/Mage.Sets/src/mage/cards/h/HazardrootHerbalist.java b/Mage.Sets/src/mage/cards/h/HazardrootHerbalist.java
index c7589565095..927905b73f1 100644
--- a/Mage.Sets/src/mage/cards/h/HazardrootHerbalist.java
+++ b/Mage.Sets/src/mage/cards/h/HazardrootHerbalist.java
@@ -2,7 +2,7 @@ package mage.cards.h;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility;
+import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.TargetObjectMatchesFilterCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
@@ -35,7 +35,7 @@ public final class HazardrootHerbalist extends CardImpl {
this.toughness = new MageInt(4);
// Whenever you attack, target creature you control gets +1/+0 until end of turn. If that creature is a token, it also gains deathtouch until end of turn.
- Ability ability = new AttacksCreatureYouControlTriggeredAbility(new BoostTargetEffect(1, 0));
+ Ability ability = new AttacksWithCreaturesTriggeredAbility(new BoostTargetEffect(1, 0), 1);
ability.addEffect(new ConditionalOneShotEffect(
new AddContinuousEffectToGame(new GainAbilityTargetEffect(DeathtouchAbility.getInstance())),
condition, "if that creature is a token, it also gains deathtouch until end of turn"
diff --git a/Mage.Sets/src/mage/cards/h/HelixPinnacle.java b/Mage.Sets/src/mage/cards/h/HelixPinnacle.java
index 23dc34ade0b..ea6cdbe8dd4 100644
--- a/Mage.Sets/src/mage/cards/h/HelixPinnacle.java
+++ b/Mage.Sets/src/mage/cards/h/HelixPinnacle.java
@@ -1,29 +1,28 @@
package mage.cards.h;
-import java.util.UUID;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.ShroudAbility;
+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 java.util.UUID;
+
/**
- *
* @author jeffwadsworth
*/
public final class HelixPinnacle extends CardImpl {
- static final String rule = "at the beginning of your upkeep, if there are 100 or more tower counters on Helix Pinnacle, you win the game";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.TOWER, 100);
public HelixPinnacle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}");
@@ -32,16 +31,12 @@ public final class HelixPinnacle extends CardImpl {
this.addAbility(ShroudAbility.getInstance());
// {X}: Put X tower counters on Helix Pinnacle.
- this.addAbility(new SimpleActivatedAbility(
- new AddCountersSourceEffect(CounterType.TOWER.createInstance(), GetXValue.instance, true),
- new ManaCostsImpl<>("{X}")));
+ this.addAbility(new SimpleActivatedAbility(new AddCountersSourceEffect(
+ CounterType.TOWER.createInstance(), GetXValue.instance, true
+ ), new ManaCostsImpl<>("{X}")));
// At the beginning of your upkeep, if there are 100 or more tower counters on Helix Pinnacle, you win the game.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()),
- new SourceHasCounterCondition(CounterType.TOWER, 100, Integer.MAX_VALUE),
- rule));
-
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition));
}
private HelixPinnacle(final HelixPinnacle card) {
diff --git a/Mage.Sets/src/mage/cards/h/HelmOfTheHost.java b/Mage.Sets/src/mage/cards/h/HelmOfTheHost.java
index fea2ab7368c..44feb75b148 100644
--- a/Mage.Sets/src/mage/cards/h/HelmOfTheHost.java
+++ b/Mage.Sets/src/mage/cards/h/HelmOfTheHost.java
@@ -54,7 +54,7 @@ class HelmOfTheHostEffect extends OneShotEffect {
HelmOfTheHostEffect() {
super(Outcome.PutCreatureInPlay);
- this.staticText = "create a token that's a copy of equipped creature, except the token isn't legendary if equipped creature is legendary. That token gains haste.";
+ this.staticText = "create a token that's a copy of equipped creature, except the token isn't legendary. That token gains haste.";
}
private HelmOfTheHostEffect(final HelmOfTheHostEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/h/HickoryWoodlot.java b/Mage.Sets/src/mage/cards/h/HickoryWoodlot.java
index 56bb98e3b48..be830460a6f 100644
--- a/Mage.Sets/src/mage/cards/h/HickoryWoodlot.java
+++ b/Mage.Sets/src/mage/cards/h/HickoryWoodlot.java
@@ -1,11 +1,9 @@
-
package mage.cards.h;
-import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.common.EntersBattlefieldTappedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -17,17 +15,21 @@ import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class HickoryWoodlot extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, ComparisonType.EQUAL_TO, 0);
+
public HickoryWoodlot(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Hickory Woodlot enters the battlefield tapped with two depletion counters on it.
Ability etbAbility = new EntersBattlefieldAbility(
@@ -35,10 +37,14 @@ public final class HickoryWoodlot extends CardImpl {
);
etbAbility.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance(2)));
this.addAbility(etbAbility);
+
// {tap}, Remove a depletion counter from Hickory Woodlot: Add {G}{G}. If there are no depletion counters on Hickory Woodlot, sacrifice it.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(2), new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.DEPLETION.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.DEPLETION, 0,0), "If there are no depletion counters on {this}, sacrifice it"));
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no depletion counters on {this}, sacrifice it"
+ ));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java b/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java
index 142ac9511d6..04110c2ed4d 100644
--- a/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java
+++ b/Mage.Sets/src/mage/cards/h/HiddenGuerrillas.java
@@ -1,4 +1,3 @@
-
package mage.cards.h;
import mage.MageInt;
@@ -11,10 +10,10 @@ 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.SubType;
+import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterArtifactSpell;
import mage.game.permanent.token.TokenImpl;
import java.util.UUID;
@@ -26,12 +25,18 @@ import java.util.UUID;
*/
public final class HiddenGuerrillas extends CardImpl {
+
+ private static final FilterSpell filter = new FilterSpell("an artifact spell");
+ static {
+ filter.add(CardType.ARTIFACT.getPredicate());
+ }
+
public HiddenGuerrillas(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}");
// When an opponent casts an artifact spell, if Hidden Guerrillas is an enchantment, Hidden Guerrillas becomes a 5/3 Soldier creature with trample.
TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new HiddenGuerrillasSoldier(), null, Duration.WhileOnBattlefield),
- new FilterArtifactSpell(), false);
+ filter, false);
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT),
"When an opponent casts an artifact spell, if {this} is an enchantment, {this} becomes a 5/3 Soldier creature with trample."));
}
diff --git a/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java b/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java
index db8f86378b5..8574ca9249d 100644
--- a/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java
+++ b/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java
@@ -33,7 +33,7 @@ public final class HikariTwilightGuardian extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, you may exile Hikari, Twilight Guardian. If you do, return it to the battlefield under its owner's control at the beginning of the next end step.
Effect effect = new ExileReturnBattlefieldOwnerNextEndStepSourceEffect();
effect.setText("you may exile {this}. If you do, return it to the battlefield under its owner's control at the beginning of the next end step");
- this.addAbility(new SpellCastControllerTriggeredAbility(effect, StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(effect, StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private HikariTwilightGuardian(final HikariTwilightGuardian card) {
diff --git a/Mage.Sets/src/mage/cards/h/HiredMuscle.java b/Mage.Sets/src/mage/cards/h/HiredMuscle.java
index d3cfa699ad1..b9d9947d089 100644
--- a/Mage.Sets/src/mage/cards/h/HiredMuscle.java
+++ b/Mage.Sets/src/mage/cards/h/HiredMuscle.java
@@ -1,37 +1,34 @@
package mage.cards.h;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FearAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.CardType;
-import mage.constants.SubType;
-import mage.constants.Duration;
-import mage.constants.SuperType;
-import mage.constants.Zone;
+import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.TokenImpl;
import mage.target.common.TargetCreaturePermanent;
+import java.util.UUID;
+
/**
* @author LevelX2
*/
public final class HiredMuscle extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.KI, 2);
public HiredMuscle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}");
@@ -44,13 +41,15 @@ public final class HiredMuscle extends CardImpl {
this.flipCardName = "Scarmaker";
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Hired Muscle.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.KI.createInstance()),
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true
+ ));
// At the beginning of the end step, if there are two or more ki counters on Hired Muscle, you may flip it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new FlipSourceEffect(new Scarmaker()), true),
- new SourceHasCounterCondition(CounterType.KI, 2, Integer.MAX_VALUE),
- "At the beginning of the end step, if there are two or more ki counters on {this}, you may flip it."));
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(
+ TargetController.NEXT, new FlipSourceEffect(new Scarmaker()).setText("flip it"), true, condition
+ ));
}
private HiredMuscle(final HiredMuscle card) {
@@ -81,6 +80,7 @@ class Scarmaker extends TokenImpl {
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
+
private Scarmaker(final Scarmaker token) {
super(token);
}
diff --git a/Mage.Sets/src/mage/cards/h/HoardersOverflow.java b/Mage.Sets/src/mage/cards/h/HoardersOverflow.java
index 5e56f53f01d..c4e5b1e300c 100644
--- a/Mage.Sets/src/mage/cards/h/HoardersOverflow.java
+++ b/Mage.Sets/src/mage/cards/h/HoardersOverflow.java
@@ -37,7 +37,7 @@ public final class HoardersOverflow extends CardImpl {
// {1}{R}, Sacrifice Hoarder's Overflow: Discard your hand, then draw cards equal to the number of stash counters on Hoarder's Overflow.
Ability ability = new SimpleActivatedAbility(new DiscardHandControllerEffect(), new ManaCostsImpl<>("{1}{R}"));
ability.addCost(new SacrificeSourceCost());
- ability.addEffect(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.STASH)).concatBy(", then"));
+ ability.addEffect(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.STASH)).setText(", then draw cards equal to the number of stash counters on {this}"));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/h/Homarid.java b/Mage.Sets/src/mage/cards/h/Homarid.java
index 6bac43f3795..5e45a30c479 100644
--- a/Mage.Sets/src/mage/cards/h/Homarid.java
+++ b/Mage.Sets/src/mage/cards/h/Homarid.java
@@ -1,57 +1,63 @@
-
package mage.cards.h;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.StateTriggeredAbility;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
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.dynamicvalue.common.CountersSourceCount;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RemoveAllCountersSourceEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
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.SubType;
-import mage.constants.Duration;
-import mage.constants.Zone;
+import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
+import java.util.UUID;
+
/**
- *
* @author LoneFox
*/
public final class Homarid extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.TIDE, ComparisonType.EQUAL_TO, 1);
+ private static final Condition condition2 = new SourceHasCounterCondition(CounterType.TIDE, ComparisonType.EQUAL_TO, 3);
+
public Homarid(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.HOMARID);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Homarid enters the battlefield with a tide counter on it.
- this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance()),
- "with a tide counter on it."));
- // At the beginning of your upkeep, put a tide counter on Homarid.
- this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.TIDE.createInstance())
+ this.addAbility(new EntersBattlefieldAbility(
+ new AddCountersSourceEffect(CounterType.TIDE.createInstance()), "with a tide counter on it."
));
+
+ // At the beginning of your upkeep, put a tide counter on Homarid.
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.TIDE.createInstance())
+ ));
+
// As long as there is exactly one tide counter on Homarid, it gets -1/-1.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
- new BoostSourceEffect(-1, -1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 1, 1),
- "As long as there is exactly one tide counter on {this}, it gets -1/-1.")));
+ new BoostSourceEffect(-1, -1, Duration.WhileOnBattlefield),
+ condition, "As long as there is exactly one tide counter on {this}, it gets -1/-1.")));
+
// As long as there are exactly three tide counters on Homarid, it gets +1/+1.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
- new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), new SourceHasCounterCondition(CounterType.TIDE, 3, 3),
- "As long as there are exactly three tide counters on {this}, it gets +1/+1.")));
+ new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield),
+ condition2, "As long as there are exactly three tide counters on {this}, it gets +1/+1."
+ )));
+
// Whenever there are four or more tide counters on Homarid, remove all tide counters from it.
- this.addAbility(new HomaridTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.TIDE)));
+ this.addAbility(new HomaridTriggeredAbility());
}
private Homarid(final Homarid card) {
@@ -66,8 +72,8 @@ public final class Homarid extends CardImpl {
class HomaridTriggeredAbility extends StateTriggeredAbility {
- HomaridTriggeredAbility(Effect effect) {
- super(Zone.BATTLEFIELD, effect);
+ HomaridTriggeredAbility() {
+ super(Zone.BATTLEFIELD, new RemoveAllCountersSourceEffect(CounterType.TIDE).setText("remove all tide counters from it"));
setTriggerPhrase("Whenever there are four or more tide counters on {this}, ");
}
diff --git a/Mage.Sets/src/mage/cards/h/HorizonSeed.java b/Mage.Sets/src/mage/cards/h/HorizonSeed.java
index be6ed2dfa74..68803b5f947 100644
--- a/Mage.Sets/src/mage/cards/h/HorizonSeed.java
+++ b/Mage.Sets/src/mage/cards/h/HorizonSeed.java
@@ -25,7 +25,7 @@ public final class HorizonSeed extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(1);
- Ability ability = new SpellCastControllerTriggeredAbility(new RegenerateTargetEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new RegenerateTargetEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/h/HowlsquadHeavy.java b/Mage.Sets/src/mage/cards/h/HowlsquadHeavy.java
index 9ad6dc1e633..84f03204171 100644
--- a/Mage.Sets/src/mage/cards/h/HowlsquadHeavy.java
+++ b/Mage.Sets/src/mage/cards/h/HowlsquadHeavy.java
@@ -9,7 +9,7 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.combat.AttacksIfAbleTargetEffect;
-import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
+import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.HasteAbility;
@@ -22,7 +22,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
-import mage.filter.StaticFilters;
+import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.game.permanent.token.GoblinToken;
@@ -36,7 +36,8 @@ import java.util.UUID;
*/
public final class HowlsquadHeavy extends CardImpl {
- private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.GOBLIN));
+ private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GOBLIN);
+ private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
private static final Hint hint = new ValueHint("Goblins you control", xValue);
public HowlsquadHeavy(UUID ownerId, CardSetInfo setInfo) {
@@ -51,10 +52,9 @@ public final class HowlsquadHeavy extends CardImpl {
this.addAbility(new StartYourEnginesAbility());
// Other Goblins you control have haste.
- this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
- HasteAbility.getInstance(), Duration.WhileOnBattlefield,
- StaticFilters.FILTER_PERMANENT_CREATURE_GOBLINS, true
- )));
+ this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect(
+ HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter, true
+ ).setText("other Goblins you control have haste")));
// At the beginning of combat on your turn, create a 1/1 red Goblin creature token. That token attacks this combat if able.
this.addAbility(new BeginningOfCombatTriggeredAbility(new HowlsquadHeavyEffect()));
diff --git a/Mage.Sets/src/mage/cards/i/IceCauldron.java b/Mage.Sets/src/mage/cards/i/IceCauldron.java
index b97b3bf8bcb..5e85395a159 100644
--- a/Mage.Sets/src/mage/cards/i/IceCauldron.java
+++ b/Mage.Sets/src/mage/cards/i/IceCauldron.java
@@ -14,8 +14,8 @@ import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.AsThoughEffect;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
@@ -38,13 +38,16 @@ import java.util.UUID;
*/
public final class IceCauldron extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, ComparisonType.EQUAL_TO, 0);
+
public IceCauldron(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {X}, {T}: Put a charge counter on Ice Cauldron and exile a nonland card from your hand. You may cast that card for as long as it remains exiled. Note the type and amount of mana spent to pay this activation cost. Activate this ability only if there are no charge counters on Ice Cauldron.
- ConditionalActivatedAbility ability = new ConditionalActivatedAbility(
- Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true), new ManaCostsImpl<>("{X}"), new SourceHasCounterCondition(CounterType.CHARGE, 0, 0));
- ability.addEffect(new IceCauldronExileEffect());
+ Ability ability = new ConditionalActivatedAbility(
+ Zone.BATTLEFIELD, new IceCauldronExileEffect(), new ManaCostsImpl<>("{X}"), condition
+ );
+ ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true));
ability.addEffect(new IceCauldronNoteManaEffect());
ability.addCost(new TapSourceCost());
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/i/InfernalKirin.java b/Mage.Sets/src/mage/cards/i/InfernalKirin.java
index cd98eedc89a..32bf5bf9e7a 100644
--- a/Mage.Sets/src/mage/cards/i/InfernalKirin.java
+++ b/Mage.Sets/src/mage/cards/i/InfernalKirin.java
@@ -37,7 +37,7 @@ public final class InfernalKirin extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, target player reveals their hand and discards all cards with that spell's converted mana cost.
Ability ability = new SpellCastControllerTriggeredAbility(
- new InfernalKirinEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD,
+ new InfernalKirinEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE,
false, SetTargetPointer.SPELL
);
ability.addTarget(new TargetPlayer());
diff --git a/Mage.Sets/src/mage/cards/i/InkEyesServantOfOni.java b/Mage.Sets/src/mage/cards/i/InkEyesServantOfOni.java
index d9ae50f79ff..d2c6655563d 100644
--- a/Mage.Sets/src/mage/cards/i/InkEyesServantOfOni.java
+++ b/Mage.Sets/src/mage/cards/i/InkEyesServantOfOni.java
@@ -13,10 +13,9 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -43,7 +42,7 @@ public final class InkEyesServantOfOni extends CardImpl {
// Whenever Ink-Eyes, Servant of Oni deals combat damage to a player, you may put target creature card from that player's graveyard onto the battlefield under your control.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true, true);
ability.addTarget(new TargetCardInGraveyard(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
// {1}{B}: Regenerate Ink-Eyes.
diff --git a/Mage.Sets/src/mage/cards/i/InnocenceKami.java b/Mage.Sets/src/mage/cards/i/InnocenceKami.java
index 9c6479f242c..cc2e3ae2e6e 100644
--- a/Mage.Sets/src/mage/cards/i/InnocenceKami.java
+++ b/Mage.Sets/src/mage/cards/i/InnocenceKami.java
@@ -16,7 +16,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.ColoredManaSymbol;
-import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.target.common.TargetCreaturePermanent;
@@ -35,7 +34,7 @@ public final class InnocenceKami extends CardImpl {
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
- this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private InnocenceKami(final InnocenceKami card) {
diff --git a/Mage.Sets/src/mage/cards/i/IntoTheFloodMaw.java b/Mage.Sets/src/mage/cards/i/IntoTheFloodMaw.java
index c0a5d0adb09..af078458bd5 100644
--- a/Mage.Sets/src/mage/cards/i/IntoTheFloodMaw.java
+++ b/Mage.Sets/src/mage/cards/i/IntoTheFloodMaw.java
@@ -39,7 +39,7 @@ public final class IntoTheFloodMaw extends CardImpl {
// Return target creature an opponent controls to its owner's hand. If the gift was promise, instead return target nonland permanent an opponent controls to its owner's hand.
this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()
- .setText("return target creature an opponent controls to its owner's hand. If the gift was promise, " +
+ .setText("return target creature an opponent controls to its owner's hand. If the gift was promised, " +
"instead return target nonland permanent an opponent controls to its owner's hand"));
this.getSpellAbility().addTarget(new TargetPermanent(playableFilter));
this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(GiftWasPromisedCondition.TRUE,
diff --git a/Mage.Sets/src/mage/cards/i/InventiveWingsmith.java b/Mage.Sets/src/mage/cards/i/InventiveWingsmith.java
index a1ede65f256..41e5960d038 100644
--- a/Mage.Sets/src/mage/cards/i/InventiveWingsmith.java
+++ b/Mage.Sets/src/mage/cards/i/InventiveWingsmith.java
@@ -1,15 +1,16 @@
package mage.cards.i;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.HaventCastSpellFromHandThisTurnCondition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+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.counters.CounterType;
@@ -24,7 +25,7 @@ public final class InventiveWingsmith extends CardImpl {
private static final Condition condition = new CompoundCondition(
"if you haven't cast a spell from your hand this turn and {this} doesn't have a flying counter on it",
HaventCastSpellFromHandThisTurnCondition.instance,
- new SourceHasCounterCondition(CounterType.FLYING, 0, 0)
+ new SourceHasCounterCondition(CounterType.FLYING, ComparisonType.EQUAL_TO, 0)
);
public InventiveWingsmith(UUID ownerId, CardSetInfo setInfo) {
diff --git a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java
index 127a351a1a7..6cbc709eefb 100644
--- a/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java
+++ b/Mage.Sets/src/mage/cards/i/IshiIshiAkkiCrackshot.java
@@ -1,14 +1,15 @@
package mage.cards.i;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SpellCastOpponentTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
-import mage.filter.common.FilterSpiritOrArcaneCard;
+import mage.filter.StaticFilters;
+
+import java.util.UUID;
/**
*
@@ -16,12 +17,6 @@ import mage.filter.common.FilterSpiritOrArcaneCard;
*/
public final class IshiIshiAkkiCrackshot extends CardImpl {
- private static final FilterSpiritOrArcaneCard filter = new FilterSpiritOrArcaneCard();
-
- static {
- filter.add(TargetController.OPPONENT.getControllerPredicate());
- }
-
public IshiIshiAkkiCrackshot(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}");
this.supertype.add(SuperType.LEGENDARY);
@@ -32,7 +27,9 @@ public final class IshiIshiAkkiCrackshot extends CardImpl {
this.toughness = new MageInt(1);
// 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"), filter, false, SetTargetPointer.PLAYER));
+ this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD,
+ new DamageTargetEffect(2, true, "that player"),
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false, SetTargetPointer.PLAYER));
}
private IshiIshiAkkiCrackshot(final IshiIshiAkkiCrackshot card) {
diff --git a/Mage.Sets/src/mage/cards/j/JadeIdol.java b/Mage.Sets/src/mage/cards/j/JadeIdol.java
index c4d4978df9f..d978bf4e6de 100644
--- a/Mage.Sets/src/mage/cards/j/JadeIdol.java
+++ b/Mage.Sets/src/mage/cards/j/JadeIdol.java
@@ -21,7 +21,7 @@ public final class JadeIdol extends CardImpl {
public JadeIdol(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
- this.addAbility(new SpellCastControllerTriggeredAbility(new BecomesCreatureSourceEffect(new JadeIdolToken(), CardType.ARTIFACT, Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new BecomesCreatureSourceEffect(new JadeIdolToken(), CardType.ARTIFACT, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private JadeIdol(final JadeIdol card) {
diff --git a/Mage.Sets/src/mage/cards/j/JamieMcCrimmon.java b/Mage.Sets/src/mage/cards/j/JamieMcCrimmon.java
index fccac5fa7f9..f33a8d92d67 100644
--- a/Mage.Sets/src/mage/cards/j/JamieMcCrimmon.java
+++ b/Mage.Sets/src/mage/cards/j/JamieMcCrimmon.java
@@ -14,8 +14,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.stack.Spell;
@@ -28,8 +27,6 @@ import java.util.UUID;
*/
public final class JamieMcCrimmon extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
-
public JamieMcCrimmon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}");
@@ -45,7 +42,7 @@ public final class JamieMcCrimmon extends CardImpl {
// Whenever you cast a historic spell, Jamie McCrimmon gets +X/+X until end of turn, where X is that spell's mana value.
this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(
JamieMcCrimmonValue.instance, JamieMcCrimmonValue.instance, Duration.EndOfTurn
- ), filter, false));
+ ), StaticFilters.FILTER_SPELL_HISTORIC, false));
// Doctor's companion
this.addAbility(DoctorsCompanionAbility.getInstance());
diff --git a/Mage.Sets/src/mage/cards/j/JensonCarthalionDruidExile.java b/Mage.Sets/src/mage/cards/j/JensonCarthalionDruidExile.java
index f5da11bd7c5..c78364cd08b 100644
--- a/Mage.Sets/src/mage/cards/j/JensonCarthalionDruidExile.java
+++ b/Mage.Sets/src/mage/cards/j/JensonCarthalionDruidExile.java
@@ -2,6 +2,7 @@ package mage.cards.j;
import mage.MageInt;
import mage.Mana;
+import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.condition.Condition;
@@ -23,7 +24,6 @@ import mage.game.permanent.token.AngelVigilanceToken;
import mage.game.stack.Spell;
import mage.util.CardUtil;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -72,15 +72,12 @@ enum JensonCarthalionDruidExileCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
- return CardUtil.castStream(
- source.getEffects()
- .stream()
- .map(effect -> effect.getValue("spellCast")),
- Spell.class
- ).findAny()
- .filter(Objects::nonNull)
- .map(spell -> spell.getColor(game).getColorCount())
- .orElse(0) >= 5;
+ return CardUtil
+ .getEffectValueFromAbility(source, "spellCast", Spell.class)
+ .map(spell -> spell.getColor(game))
+ .map(ObjectColor::getColorCount)
+ .filter(x -> x >= 5)
+ .isPresent();
}
@Override
diff --git a/Mage.Sets/src/mage/cards/j/JeweledAmulet.java b/Mage.Sets/src/mage/cards/j/JeweledAmulet.java
index 3c00ce79b48..995ff03bb1a 100644
--- a/Mage.Sets/src/mage/cards/j/JeweledAmulet.java
+++ b/Mage.Sets/src/mage/cards/j/JeweledAmulet.java
@@ -2,18 +2,20 @@ package mage.cards.j;
import mage.Mana;
import mage.abilities.Ability;
+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.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.OneShotEffect;
-import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.effects.mana.ManaEffect;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
@@ -29,14 +31,16 @@ import java.util.UUID;
*/
public final class JeweledAmulet extends CardImpl {
- private static final String rule = "{1}, {T}: Put a charge counter on {this}. Note the type of mana spent to pay this activation cost. Activate only if there are no charge counters on {this}.";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, ComparisonType.EQUAL_TO, 0);
public JeweledAmulet(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}");
// {1}, {tap}: Put a charge counter on Jeweled Amulet. Note the type of mana spent to pay this activation cost. Activate this ability only if there are no charge counters on Jeweled Amulet.
- ConditionalActivatedAbility ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new JeweledAmuletAddCounterEffect(), new ManaCostsImpl<>("{1}"), new SourceHasCounterCondition(CounterType.CHARGE, 0, 0), rule);
- ability.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true));
+ ConditionalActivatedAbility ability = new ConditionalActivatedAbility(
+ new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), true), new GenericManaCost(1), condition
+ );
+ ability.addEffect(new JeweledAmuletAddCounterEffect());
ability.addCost(new TapSourceCost());
this.addAbility(ability);
@@ -44,7 +48,6 @@ public final class JeweledAmulet extends CardImpl {
Ability ability2 = new SimpleManaAbility(Zone.BATTLEFIELD, new JeweledAmuletAddManaEffect(), new TapSourceCost());
ability2.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()));
this.addAbility(ability2);
-
}
private JeweledAmulet(final JeweledAmulet card) {
@@ -63,7 +66,7 @@ class JeweledAmuletAddCounterEffect extends OneShotEffect {
public JeweledAmuletAddCounterEffect() {
super(Outcome.Benefit);
- this.staticText = "Note the type of mana spent to pay this activation cost. Activate only if there are no charge counters on {this}";
+ this.staticText = "Note the type of mana spent to pay this activation cost";
}
private JeweledAmuletAddCounterEffect(final JeweledAmuletAddCounterEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/j/JhoiraWeatherlightCaptain.java b/Mage.Sets/src/mage/cards/j/JhoiraWeatherlightCaptain.java
index 2607fa6334d..b1290ef5049 100644
--- a/Mage.Sets/src/mage/cards/j/JhoiraWeatherlightCaptain.java
+++ b/Mage.Sets/src/mage/cards/j/JhoiraWeatherlightCaptain.java
@@ -8,15 +8,12 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import java.util.UUID;
public final class JhoiraWeatherlightCaptain extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
-
public JhoiraWeatherlightCaptain(UUID ownerId, CardSetInfo cardSetInfo) {
super(ownerId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{R}");
this.supertype.add(SuperType.LEGENDARY);
@@ -28,7 +25,7 @@ public final class JhoiraWeatherlightCaptain extends CardImpl {
this.addAbility(new SpellCastControllerTriggeredAbility(
new DrawCardSourceControllerEffect(1)
.setText("draw a card. (Artifacts, legendaries, and Sagas are historic.)"),
- filter, false
+ StaticFilters.FILTER_SPELL_HISTORIC, false
));
}
diff --git a/Mage.Sets/src/mage/cards/j/JhoirasFamiliar.java b/Mage.Sets/src/mage/cards/j/JhoirasFamiliar.java
index 9d1c4a37870..c22a762c16e 100644
--- a/Mage.Sets/src/mage/cards/j/JhoirasFamiliar.java
+++ b/Mage.Sets/src/mage/cards/j/JhoirasFamiliar.java
@@ -1,7 +1,6 @@
package mage.cards.j;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
@@ -10,8 +9,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
+
+import java.util.UUID;
/**
*
@@ -19,6 +20,11 @@ import mage.filter.common.FilterHistoricCard;
*/
public final class JhoirasFamiliar extends CardImpl {
+ private static final FilterCard filter = new FilterCard("historic spells");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
+
public JhoirasFamiliar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}");
@@ -31,7 +37,7 @@ public final class JhoirasFamiliar extends CardImpl {
// Historic spells you cast cost {1} less to cast.
this.addAbility(new SimpleStaticAbility(
- new SpellsCostReductionControllerEffect(new FilterHistoricCard(), 1)
+ new SpellsCostReductionControllerEffect(filter, 1)
.setText("Historic spells you cast cost {1} less to cast. (Artifacts, legendaries, and Sagas are historic.)")));
}
diff --git a/Mage.Sets/src/mage/cards/j/JoGrant.java b/Mage.Sets/src/mage/cards/j/JoGrant.java
index d6c4ef8593e..2fc65909432 100644
--- a/Mage.Sets/src/mage/cards/j/JoGrant.java
+++ b/Mage.Sets/src/mage/cards/j/JoGrant.java
@@ -15,7 +15,7 @@ import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.game.Game;
import mage.players.Player;
@@ -59,7 +59,10 @@ public final class JoGrant extends CardImpl {
class JoGrantEffect extends ContinuousEffectImpl {
- private static final FilterCard filter = new FilterHistoricCard();
+ private static final FilterCard filter = new FilterCard("historic card");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
JoGrantEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
diff --git a/Mage.Sets/src/mage/cards/j/JoragaInvocation.java b/Mage.Sets/src/mage/cards/j/JoragaInvocation.java
index 9c528fee3af..349ec87d4d2 100644
--- a/Mage.Sets/src/mage/cards/j/JoragaInvocation.java
+++ b/Mage.Sets/src/mage/cards/j/JoragaInvocation.java
@@ -1,7 +1,5 @@
-
package mage.cards.j;
-import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
@@ -18,8 +16,9 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
+import java.util.UUID;
+
/**
- *
* @author LevelX2
*/
public final class JoragaInvocation extends CardImpl {
@@ -28,9 +27,9 @@ public final class JoragaInvocation extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}");
// Each creature you control gets +3/+3 until end of turn and must be blocked this turn if able.
- this.getSpellAbility().addEffect(new BoostControlledEffect(3, 3, Duration.EndOfTurn));
+ this.getSpellAbility().addEffect(new BoostControlledEffect(3, 3, Duration.EndOfTurn)
+ .setText("each creature you control gets +3/+3 until end of turn"));
this.getSpellAbility().addEffect(new JoragaInvocationEffect());
-
}
private JoragaInvocation(final JoragaInvocation card) {
diff --git a/Mage.Sets/src/mage/cards/k/KaitoBaneOfNightmares.java b/Mage.Sets/src/mage/cards/k/KaitoBaneOfNightmares.java
index f7d515aa699..af7f274d3cf 100644
--- a/Mage.Sets/src/mage/cards/k/KaitoBaneOfNightmares.java
+++ b/Mage.Sets/src/mage/cards/k/KaitoBaneOfNightmares.java
@@ -63,7 +63,7 @@ public final class KaitoBaneOfNightmares extends CardImpl {
// 0: Surveil 2. Then draw a card for each opponent who lost life this turn.
Ability ability = new LoyaltyAbility(new SurveilEffect(2), 0);
- ability.addEffect(new DrawCardSourceControllerEffect(KaitoBaneOfNightmaresCount.instance));
+ ability.addEffect(new DrawCardSourceControllerEffect(KaitoBaneOfNightmaresCount.instance).concatBy("Then"));
this.addAbility(ability);
// -2: Tap target creature. Put two stun counters on it.
diff --git a/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java b/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java
index 6cec34514c2..6cffb041ca4 100644
--- a/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java
+++ b/Mage.Sets/src/mage/cards/k/KalamaxTheStormsire.java
@@ -13,7 +13,7 @@ import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.counters.CounterType;
-import mage.filter.common.FilterInstantSpell;
+import mage.filter.FilterSpell;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@@ -55,8 +55,14 @@ public final class KalamaxTheStormsire extends CardImpl {
}
class KalamaxTheStormsireSpellCastAbility extends SpellCastControllerTriggeredAbility {
+
+ private static final FilterSpell filterInstant = new FilterSpell();
+ static {
+ filterInstant.add(CardType.INSTANT.getPredicate());
+ }
+
KalamaxTheStormsireSpellCastAbility() {
- super(new CopyTargetStackObjectEffect(true), new FilterInstantSpell(), false);
+ super(new CopyTargetStackObjectEffect(true), filterInstant, false);
}
private KalamaxTheStormsireSpellCastAbility(final KalamaxTheStormsireSpellCastAbility ability) {
diff --git a/Mage.Sets/src/mage/cards/k/KamiOfFiresRoar.java b/Mage.Sets/src/mage/cards/k/KamiOfFiresRoar.java
index c1786031541..98290b3d4b1 100644
--- a/Mage.Sets/src/mage/cards/k/KamiOfFiresRoar.java
+++ b/Mage.Sets/src/mage/cards/k/KamiOfFiresRoar.java
@@ -28,7 +28,7 @@ public final class KamiOfFiresRoar extends CardImpl {
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, target creature can't block this turn.
- Ability ability = new SpellCastControllerTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/k/KamiOfTatteredShoji.java b/Mage.Sets/src/mage/cards/k/KamiOfTatteredShoji.java
index 8ef007fa0cc..800b79ba3b1 100644
--- a/Mage.Sets/src/mage/cards/k/KamiOfTatteredShoji.java
+++ b/Mage.Sets/src/mage/cards/k/KamiOfTatteredShoji.java
@@ -26,7 +26,7 @@ public final class KamiOfTatteredShoji extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(5);
// Whenever you cast a Spirit or Arcane spell, Kami of Tattered Shoji gains flying until end of turn.
- this.addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private KamiOfTatteredShoji(final KamiOfTatteredShoji card) {
diff --git a/Mage.Sets/src/mage/cards/k/KamiOfTheHunt.java b/Mage.Sets/src/mage/cards/k/KamiOfTheHunt.java
index 81d1d7666aa..cc7d3610941 100644
--- a/Mage.Sets/src/mage/cards/k/KamiOfTheHunt.java
+++ b/Mage.Sets/src/mage/cards/k/KamiOfTheHunt.java
@@ -24,7 +24,7 @@ public final class KamiOfTheHunt extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(2);
- this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private KamiOfTheHunt(final KamiOfTheHunt card) {
diff --git a/Mage.Sets/src/mage/cards/k/KamiOfThePaintedRoad.java b/Mage.Sets/src/mage/cards/k/KamiOfThePaintedRoad.java
index eb3e982a985..3eec67e8e27 100644
--- a/Mage.Sets/src/mage/cards/k/KamiOfThePaintedRoad.java
+++ b/Mage.Sets/src/mage/cards/k/KamiOfThePaintedRoad.java
@@ -26,7 +26,7 @@ public final class KamiOfThePaintedRoad extends CardImpl {
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, Kami of the Painted Road gains protection from the color of your choice until end of turn.
- this.addAbility(new SpellCastControllerTriggeredAbility(new GainProtectionFromColorSourceEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new GainProtectionFromColorSourceEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
diff --git a/Mage.Sets/src/mage/cards/k/KamiOfTheWaningMoon.java b/Mage.Sets/src/mage/cards/k/KamiOfTheWaningMoon.java
index 84a3858e174..a115270f7e0 100644
--- a/Mage.Sets/src/mage/cards/k/KamiOfTheWaningMoon.java
+++ b/Mage.Sets/src/mage/cards/k/KamiOfTheWaningMoon.java
@@ -29,7 +29,7 @@ public final class KamiOfTheWaningMoon extends CardImpl {
this.power = new MageInt(1);
this.toughness = new MageInt(1);
this.addAbility(FlyingAbility.getInstance());
- Ability ability = new SpellCastControllerTriggeredAbility(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/k/KarakykGuardian.java b/Mage.Sets/src/mage/cards/k/KarakykGuardian.java
index 6fd569725a6..01151692af5 100644
--- a/Mage.Sets/src/mage/cards/k/KarakykGuardian.java
+++ b/Mage.Sets/src/mage/cards/k/KarakykGuardian.java
@@ -1,10 +1,8 @@
package mage.cards.k;
import mage.MageInt;
-import mage.MageObjectReference;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.condition.Condition;
+import mage.abilities.condition.common.SourceHasntDealtDamageThisGameCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlyingAbility;
@@ -15,14 +13,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.WatcherScope;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.watchers.Watcher;
+import mage.watchers.common.DealtDamageThisGameWatcher;
-import java.util.HashSet;
-import java.util.Set;
import java.util.UUID;
/**
@@ -49,8 +41,9 @@ public final class KarakykGuardian extends CardImpl {
// This creature has hexproof if it hasn't dealt damage yet.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(HexproofAbility.getInstance()),
- KarakykGuardianCondition.instance, "{this} has hexproof if it hasn't dealt damage yet"
- )), new KarakykGuardianWatcher());
+ SourceHasntDealtDamageThisGameCondition.instance,
+ "{this} has hexproof if it hasn't dealt damage yet"
+ )).addHint(SourceHasntDealtDamageThisGameCondition.getHint()), new DealtDamageThisGameWatcher());
}
private KarakykGuardian(final KarakykGuardian card) {
@@ -62,49 +55,3 @@ public final class KarakykGuardian extends CardImpl {
return new KarakykGuardian(this);
}
}
-
-enum KarakykGuardianCondition implements Condition {
-
- instance;
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent permanent = game.getPermanent(source.getSourceId());
- KarakykGuardianWatcher watcher = game.getState().getWatcher(KarakykGuardianWatcher.class);
- return permanent != null && !watcher.getDamagers().contains(new MageObjectReference(permanent, game));
- }
-
- @Override
- public String toString() {
- return "{this} hasn't dealt damage yet";
- }
-
-}
-
-class KarakykGuardianWatcher extends Watcher {
-
- private final Set damagers = new HashSet<>();
-
- public KarakykGuardianWatcher() {
- super(WatcherScope.GAME);
- }
-
- @Override
- public void watch(GameEvent event, Game game) {
- switch (event.getType()) {
- case DAMAGED_PERMANENT:
- case DAMAGED_PLAYER:
- break;
- default:
- return;
- }
- Permanent permanent = game.getPermanent(event.getSourceId());
- if (permanent != null) {
- damagers.add(new MageObjectReference(permanent, game));
- }
- }
-
- public Set getDamagers() {
- return damagers;
- }
-}
diff --git a/Mage.Sets/src/mage/cards/k/KemuriOnna.java b/Mage.Sets/src/mage/cards/k/KemuriOnna.java
index ac916b867b4..96189a95f97 100644
--- a/Mage.Sets/src/mage/cards/k/KemuriOnna.java
+++ b/Mage.Sets/src/mage/cards/k/KemuriOnna.java
@@ -33,7 +33,7 @@ public final class KemuriOnna extends CardImpl {
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
// Whenever you cast a Spirit or Arcane spell, you may return Kemuri-Onna to its owner's hand.
- this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private KemuriOnna(final KemuriOnna card) {
diff --git a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java
index 2007ecb6737..02308a13a9f 100644
--- a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java
+++ b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java
@@ -56,7 +56,7 @@ class KheruSpellsnatcherEffect extends OneShotEffect {
super(Outcome.Benefit);
this.staticText = "counter target spell. If that spell is countered this way, "
+ "exile it instead of putting it into its owner's graveyard. "
- + "You may cast that card without paying its mana cost as long as it remains exiled";
+ + "You may cast that card without paying its mana cost for as long as it remains exiled";
}
private KheruSpellsnatcherEffect(final KheruSpellsnatcherEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/k/KiriOnna.java b/Mage.Sets/src/mage/cards/k/KiriOnna.java
index 8328d3b120d..8a0a715f536 100644
--- a/Mage.Sets/src/mage/cards/k/KiriOnna.java
+++ b/Mage.Sets/src/mage/cards/k/KiriOnna.java
@@ -33,7 +33,7 @@ public final class KiriOnna extends CardImpl {
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
// Whenever you cast a Spirit or Arcane spell, you may return Kiri-Onna to its owner's hand.
- this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private KiriOnna(final KiriOnna card) {
diff --git a/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java b/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java
index 09d03710924..254d48fc2e5 100644
--- a/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java
+++ b/Mage.Sets/src/mage/cards/k/KirinTouchedOrochi.java
@@ -17,9 +17,9 @@ 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.common.FilterCreatureCard;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.permanent.token.SpiritToken;
import mage.players.Player;
@@ -32,7 +32,10 @@ import mage.target.common.TargetControlledCreaturePermanent;
*/
public final class KirinTouchedOrochi extends CardImpl {
- private static final FilterNoncreatureCard filter2 = new FilterNoncreatureCard("noncreature card from a graveyard");
+ 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}, "");
@@ -51,7 +54,7 @@ public final class KirinTouchedOrochi extends CardImpl {
// • 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(filter2));
+ mode.addTarget(new TargetCardInGraveyard(filter));
ability.addMode(mode);
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/k/Knightfisher.java b/Mage.Sets/src/mage/cards/k/Knightfisher.java
index 35291fcb2e9..3f54f354aa4 100644
--- a/Mage.Sets/src/mage/cards/k/Knightfisher.java
+++ b/Mage.Sets/src/mage/cards/k/Knightfisher.java
@@ -1,7 +1,7 @@
package mage.cards.k;
import mage.MageInt;
-import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
+import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
@@ -9,6 +9,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledPermanent;
+import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.permanent.token.FishNoAbilityToken;
@@ -19,9 +21,10 @@ import java.util.UUID;
*/
public final class Knightfisher extends CardImpl {
- private static final FilterPermanent filter = new FilterPermanent(SubType.BIRD, "nontoken Bird");
+ private static final FilterPermanent filter = new FilterControlledPermanent(SubType.BIRD, "another nontoken Bird you control");
static {
+ filter.add(AnotherPredicate.instance);
filter.add(TokenPredicate.FALSE);
}
@@ -37,9 +40,7 @@ public final class Knightfisher extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever another nontoken Bird you control enters, create a 1/1 blue Fish creature token.
- this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
- new CreateTokenEffect(new FishNoAbilityToken()), filter
- ));
+ this.addAbility(new EntersBattlefieldAllTriggeredAbility(new CreateTokenEffect(new FishNoAbilityToken()), filter));
}
private Knightfisher(final Knightfisher card) {
diff --git a/Mage.Sets/src/mage/cards/k/KodamaOfTheSouthTree.java b/Mage.Sets/src/mage/cards/k/KodamaOfTheSouthTree.java
index b0562ec0d0d..8c00fb6b64c 100644
--- a/Mage.Sets/src/mage/cards/k/KodamaOfTheSouthTree.java
+++ b/Mage.Sets/src/mage/cards/k/KodamaOfTheSouthTree.java
@@ -29,7 +29,7 @@ public final class KodamaOfTheSouthTree extends CardImpl {
this.power = new MageInt(4);
this.toughness = new MageInt(4);
- Ability ability = new SpellCastControllerTriggeredAbility(new BoostControlledEffect(1, 1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new BoostControlledEffect(1, 1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addEffect(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, true));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/k/KyokiSanitysEclipse.java b/Mage.Sets/src/mage/cards/k/KyokiSanitysEclipse.java
index 80ad8e4e972..1395961e371 100644
--- a/Mage.Sets/src/mage/cards/k/KyokiSanitysEclipse.java
+++ b/Mage.Sets/src/mage/cards/k/KyokiSanitysEclipse.java
@@ -32,7 +32,7 @@ public final class KyokiSanitysEclipse extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, target opponent exiles a card from their hand.
Ability ability = new SpellCastControllerTriggeredAbility(
new ExileFromZoneTargetEffect(Zone.HAND, false),
- StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false
);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/l/LandCap.java b/Mage.Sets/src/mage/cards/l/LandCap.java
index b0e41ca6f37..d2d40f20d1b 100644
--- a/Mage.Sets/src/mage/cards/l/LandCap.java
+++ b/Mage.Sets/src/mage/cards/l/LandCap.java
@@ -1,50 +1,50 @@
-
package mage.cards.l;
-import java.util.UUID;
-import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.mana.SimpleManaAbility;
+import mage.abilities.mana.BlueManaAbility;
+import mage.abilities.mana.WhiteManaAbility;
+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 java.util.UUID;
+
/**
- *
* @author Luna Skyrise
*/
public final class LandCap extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION);
+
public LandCap(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Land Cap doesn't untap during your untap step if it has a depletion counter on it.
- Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true),
- new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE));
- effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it");
- Ability ability = new SimpleStaticAbility(effect);
- this.addAbility(ability);
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(
+ new DontUntapInControllersUntapStepSourceEffect(false, true), condition
+ ).setText("{this} doesn't untap during your untap step if it has a depletion counter on it")));
+
// At the beginning of your upkeep, remove a depletion counter from Land Cap.
- Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability2);
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance())
+ ));
+
// {T}: Add {W} or {U}. Put a depletion counter on Land Cap.
- Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
- ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability3);
- Ability ability4 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlueMana(1), new TapSourceCost());
- ability4.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability4);
+ Ability ability = new WhiteManaAbility();
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability);
+ Ability ability2 = new BlueManaAbility();
+ ability2.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability2);
}
private LandCap(final LandCap card) {
diff --git a/Mage.Sets/src/mage/cards/l/LatullasOrders.java b/Mage.Sets/src/mage/cards/l/LatullasOrders.java
index c3ca0307682..3e274506c02 100644
--- a/Mage.Sets/src/mage/cards/l/LatullasOrders.java
+++ b/Mage.Sets/src/mage/cards/l/LatullasOrders.java
@@ -15,7 +15,7 @@ import mage.constants.SubType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -45,7 +45,7 @@ public final class LatullasOrders extends CardImpl {
new DestroyTargetEffect(), "enchanted creature", true, true
).setTriggerPhrase("Whenever enchanted creature deals combat damage to defending player, ");
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/l/LavaTubes.java b/Mage.Sets/src/mage/cards/l/LavaTubes.java
index 78de147fb20..23c02380bd9 100644
--- a/Mage.Sets/src/mage/cards/l/LavaTubes.java
+++ b/Mage.Sets/src/mage/cards/l/LavaTubes.java
@@ -1,50 +1,51 @@
package mage.cards.l;
-import java.util.UUID;
-import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.mana.SimpleManaAbility;
+import mage.abilities.mana.BlackManaAbility;
+import mage.abilities.mana.RedManaAbility;
+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 java.util.UUID;
+
/**
- *
* @author Luna Skyrise
*/
public final class LavaTubes extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION);
+
public LavaTubes(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Lava Tubes doesn't untap during your untap step if it has a depletion counter on it.
- Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true),
- new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE));
- effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it");
- Ability ability = new SimpleStaticAbility(effect);
- this.addAbility(ability);
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(
+ new DontUntapInControllersUntapStepSourceEffect(false, true), condition
+ ).setText("{this} doesn't untap during your untap step if it has a depletion counter on it")));
+
// At the beginning of your upkeep, remove a depletion counter from Lava Tubes.
- Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability2);
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance())
+ ));
+
// {tap}: Add {B} or {R}. Put a depletion counter on Lava Tubes.
- Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new TapSourceCost());
- ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability3);
- Ability ability4 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(1), new TapSourceCost());
- ability4.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability4);
+ Ability ability = new BlackManaAbility();
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability);
+ Ability ability2 = new RedManaAbility();
+ ability2.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability2);
}
private LavaTubes(final LavaTubes card) {
diff --git a/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java
index 5dd5ac6e8d5..534cbbc9dd3 100644
--- a/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java
+++ b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java
@@ -42,7 +42,7 @@ public final class LaviniaAzoriusRenegade extends CardImpl {
// Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell.
this.addAbility(new SpellCastOpponentTriggeredAbility(
Zone.BATTLEFIELD, new CounterTargetEffect(),
- StaticFilters.FILTER_SPELL_NO_MANA_SPENT, false, true
+ StaticFilters.FILTER_SPELL_NO_MANA_SPENT, false
));
}
diff --git a/Mage.Sets/src/mage/cards/l/LaylaHassan.java b/Mage.Sets/src/mage/cards/l/LaylaHassan.java
index b3eaf7c2a2e..d18f44ca3b6 100644
--- a/Mage.Sets/src/mage/cards/l/LaylaHassan.java
+++ b/Mage.Sets/src/mage/cards/l/LaylaHassan.java
@@ -1,19 +1,7 @@
package mage.cards.l;
-import java.util.UUID;
import mage.MageInt;
-import mage.constants.SubType;
-import mage.constants.SuperType;
-import mage.constants.Zone;
-import mage.filter.common.FilterCreaturePermanent;
-import mage.filter.common.FilterHistoricCard;
-import mage.game.Game;
-import mage.game.events.DamagedBatchForOnePlayerEvent;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.target.common.TargetCardInYourGraveyard;
import mage.abilities.Ability;
-import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.OneOrMoreDamagePlayerTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
@@ -21,13 +9,26 @@ import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.SuperType;
+import mage.filter.FilterCard;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.mageobject.HistoricPredicate;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.target.common.TargetCardInYourGraveyard;
+
+import java.util.UUID;
/**
* @author balazskristof
*/
public final class LaylaHassan extends CardImpl {
- private static final FilterHistoricCard filter = new FilterHistoricCard("historic card from your graveyard");
+ private static final FilterCard filter = new FilterCard("historic card from your graveyard");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
public LaylaHassan(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
diff --git a/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java b/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java
index 0c7345f43cb..86c13e6ed56 100644
--- a/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java
+++ b/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java
@@ -4,14 +4,15 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
+import mage.abilities.condition.Condition;
+import mage.abilities.condition.common.SourceMatchesFilterCondition;
import mage.abilities.dynamicvalue.common.CreaturesYouControlCount;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.combat.GoadTargetEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
-import mage.abilities.hint.ValueHint;
+import mage.abilities.hint.common.CreaturesYouControlHint;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TrampleAbility;
@@ -21,13 +22,14 @@ 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.TokenPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
-import mage.game.permanent.PermanentToken;
import mage.target.targetpointer.FixedTargets;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
import java.util.UUID;
/**
@@ -35,6 +37,14 @@ import java.util.UUID;
*/
public final class LifeOfTheParty extends CardImpl {
+ private static final FilterPermanent filter = new FilterPermanent("it's not a token");
+
+ static {
+ filter.add(TokenPredicate.FALSE);
+ }
+
+ private static final Condition condition = new SourceMatchesFilterCondition(filter);
+
public LifeOfTheParty(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
@@ -55,15 +65,11 @@ public final class LifeOfTheParty extends CardImpl {
this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(
CreaturesYouControlCount.instance, StaticValue.get(0),
Duration.EndOfTurn, "it"
- ).setText("it gets +X/+0 until end of turn, where X is the number of creatures you control")
- ).addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.instance)));
+ ).setText("it gets +X/+0 until end of turn, where X is the number of creatures you control"))
+ .addHint(CreaturesYouControlHint.instance));
// When Life of the Party enters the battlefield, if it's not a token, each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new LifeOfThePartyEffect()), LifeOfTheParty::checkSource,
- "When {this} enters, if it's not a token, each opponent creates a " +
- "token that's a copy of it. The tokens are goaded for the rest of the game."
- ));
+ this.addAbility(new EntersBattlefieldTriggeredAbility(new LifeOfThePartyEffect()).withInterveningIf(condition));
}
private LifeOfTheParty(final LifeOfTheParty card) {
@@ -74,16 +80,13 @@ public final class LifeOfTheParty extends CardImpl {
public LifeOfTheParty copy() {
return new LifeOfTheParty(this);
}
-
- static boolean checkSource(Game game, Ability source) {
- return !(source.getSourcePermanentOrLKI(game) instanceof PermanentToken);
- }
}
class LifeOfThePartyEffect extends OneShotEffect {
LifeOfThePartyEffect() {
super(Outcome.Benefit);
+ staticText = "each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game";
}
private LifeOfThePartyEffect(final LifeOfThePartyEffect effect) {
@@ -101,7 +104,7 @@ class LifeOfThePartyEffect extends OneShotEffect {
if (permanent == null) {
return false;
}
- List permanents = new ArrayList<>();
+ Set permanents = new HashSet<>();
for (UUID playerId : game.getOpponents(source.getControllerId())) {
CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(playerId);
effect.setSavedPermanent(permanent);
@@ -111,12 +114,8 @@ class LifeOfThePartyEffect extends OneShotEffect {
if (permanents.isEmpty()) {
return false;
}
- game.addEffect(
- new GoadTargetEffect()
- .setDuration(Duration.EndOfGame)
- .setTargetPointer(new FixedTargets(permanents, game)),
- source
- );
+ game.addEffect(new GoadTargetEffect(Duration.EndOfGame)
+ .setTargetPointer(new FixedTargets(permanents, game)), source);
return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/l/LifecraftEngine.java b/Mage.Sets/src/mage/cards/l/LifecraftEngine.java
index dae3206bb16..f7d3493c669 100644
--- a/Mage.Sets/src/mage/cards/l/LifecraftEngine.java
+++ b/Mage.Sets/src/mage/cards/l/LifecraftEngine.java
@@ -68,7 +68,7 @@ class LifecraftEngineAddSubTypeAllEffect extends ContinuousEffectImpl {
public LifecraftEngineAddSubTypeAllEffect() {
super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
- staticText = "Vehicle creatures you control are the chosen type in addition to their other types.";
+ staticText = "Vehicle creatures you control are the chosen creature type in addition to their other types.";
}
private LifecraftEngineAddSubTypeAllEffect(final LifecraftEngineAddSubTypeAllEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java b/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java
new file mode 100644
index 00000000000..450b5f036bf
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/l/LifestreamsBlessing.java
@@ -0,0 +1,141 @@
+package mage.cards.l;
+
+import mage.MageInt;
+import mage.MageObject;
+import mage.MageObjectReference;
+import mage.abilities.Ability;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.DrawCardSourceControllerEffect;
+import mage.abilities.effects.common.GainLifeEffect;
+import mage.abilities.keyword.ForetellAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.WatcherScope;
+import mage.constants.Zone;
+import mage.filter.StaticFilters;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.stack.Spell;
+import mage.watchers.Watcher;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class LifestreamsBlessing extends CardImpl {
+
+ public LifestreamsBlessing(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{G}{G}");
+
+ // Draw X cards, where X is the greatest power among creatures you controlled as you cast this spell. If this spell was cast from exile, you gain twice X life.
+ this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(LifestreamsBlessingValue.ONCE));
+ this.getSpellAbility().addEffect(new GainLifeEffect(LifestreamsBlessingValue.TWICE)
+ .setText("if this spell was cast from exile, you gain twice X life"));
+ this.getSpellAbility().addWatcher(new LifestreamsBlessingWatcher());
+
+ // Foretell {4}{G}
+ this.addAbility(new ForetellAbility(this, "{4}{G}"));
+ }
+
+ private LifestreamsBlessing(final LifestreamsBlessing card) {
+ super(card);
+ }
+
+ @Override
+ public LifestreamsBlessing copy() {
+ return new LifestreamsBlessing(this);
+ }
+}
+
+enum LifestreamsBlessingValue implements DynamicValue {
+ ONCE(false),
+ TWICE(true);
+ private final boolean flag;
+
+ LifestreamsBlessingValue(boolean flag) {
+ this.flag = flag;
+ }
+
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ if (flag && !Optional
+ .ofNullable(sourceAbility)
+ .map(Ability::getSourceId)
+ .map(game::getSpell)
+ .map(Spell::getFromZone)
+ .map(Zone.EXILED::match)
+ .orElse(false)) {
+ return 0;
+ }
+ return (flag ? 2 : 1) * LifestreamsBlessingWatcher.getValue(game, sourceAbility);
+ }
+
+ @Override
+ public LifestreamsBlessingValue copy() {
+ return this;
+ }
+
+ @Override
+ public String getMessage() {
+ return "the greatest power among creatures you controlled as you cast this spell";
+ }
+
+ @Override
+ public String toString() {
+ return "X";
+ }
+}
+
+class LifestreamsBlessingWatcher extends Watcher {
+
+ private final Map map = new HashMap<>();
+
+ LifestreamsBlessingWatcher() {
+ 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) {
+ return;
+ }
+ map.put(
+ new MageObjectReference(spell.getSpellAbility().getSourceId(), game),
+ game.getBattlefield()
+ .getActivePermanents(
+ StaticFilters.FILTER_CONTROLLED_CREATURE, spell.getControllerId(), game
+ )
+ .stream()
+ .map(MageObject::getPower)
+ .mapToInt(MageInt::getValue)
+ .max()
+ .orElse(0)
+ );
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ map.clear();
+ }
+
+ static int getValue(Game game, Ability source) {
+ return game
+ .getState()
+ .getWatcher(LifestreamsBlessingWatcher.class)
+ .map
+ .getOrDefault(new MageObjectReference(
+ source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game
+ ), 0);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/l/Lightwalker.java b/Mage.Sets/src/mage/cards/l/Lightwalker.java
index 3ddc8f25aef..c6877f09737 100644
--- a/Mage.Sets/src/mage/cards/l/Lightwalker.java
+++ b/Mage.Sets/src/mage/cards/l/Lightwalker.java
@@ -1,9 +1,8 @@
-
package mage.cards.l;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
@@ -12,26 +11,29 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
-import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author fireshoes
*/
public final class Lightwalker extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1);
+
public Lightwalker(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WARRIOR);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
- // Lightwalker has flying as long as it has a +1/+1 counter on it.
- this.addAbility(new SimpleStaticAbility(
- new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()),
- new SourceHasCounterCondition(CounterType.P1P1),"Lightwalker has flying as long as it has a +1/+1 counter on it")));
+ // Lightwalker has flying as long as it has a +1/+1 counter on it.
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
+ new GainAbilitySourceEffect(FlyingAbility.getInstance()), condition,
+ "{this} has flying as long as it has a +1/+1 counter on it"
+ )));
}
private Lightwalker(final Lightwalker card) {
diff --git a/Mage.Sets/src/mage/cards/l/LightwielderPaladin.java b/Mage.Sets/src/mage/cards/l/LightwielderPaladin.java
index 00d395d0cbd..3203a1ebd15 100644
--- a/Mage.Sets/src/mage/cards/l/LightwielderPaladin.java
+++ b/Mage.Sets/src/mage/cards/l/LightwielderPaladin.java
@@ -15,7 +15,7 @@ import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -46,7 +46,7 @@ public final class LightwielderPaladin extends CardImpl {
// Whenever Lightwielder Paladin deals combat damage to a player, you may exile target black or red permanent that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ExileTargetEffect(), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java
index fb1032599f5..10978d95a8d 100644
--- a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java
+++ b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java
@@ -103,9 +103,7 @@ class LlawanCephalidRuleModifyingEffect extends ContinuousRuleModifyingEffectImp
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && game.isOpponent(controller, event.getPlayerId())) {
Card card = game.getCard(event.getSourceId());
- if (card != null && filter.match(card, source.getControllerId(), game)) {
- return true;
- }
+ return card != null && filter.match(card, source.getControllerId(), source, game);
}
return false;
}
diff --git a/Mage.Sets/src/mage/cards/l/LoamDweller.java b/Mage.Sets/src/mage/cards/l/LoamDweller.java
index 989ea0a8066..6aaad407200 100644
--- a/Mage.Sets/src/mage/cards/l/LoamDweller.java
+++ b/Mage.Sets/src/mage/cards/l/LoamDweller.java
@@ -27,7 +27,7 @@ public final class LoamDweller extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, you may put a land card from your hand onto the battlefield tapped.
this.addAbility(new SpellCastControllerTriggeredAbility(
new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A, false, true),
- StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private LoamDweller(final LoamDweller card) {
diff --git a/Mage.Sets/src/mage/cards/l/LongstalkBrawl.java b/Mage.Sets/src/mage/cards/l/LongstalkBrawl.java
index db52e9e26b8..e6032504f7e 100644
--- a/Mage.Sets/src/mage/cards/l/LongstalkBrawl.java
+++ b/Mage.Sets/src/mage/cards/l/LongstalkBrawl.java
@@ -33,7 +33,7 @@ public final class LongstalkBrawl extends CardImpl {
GiftWasPromisedCondition.TRUE, "choose target creature you control and target creature " +
"you don't control. Put a +1/+1 counter on the creature you control if the gift was promised"
));
- this.getSpellAbility().addEffect(new FightTargetsEffect().setText("then those creatures fight each other"));
+ this.getSpellAbility().addEffect(new FightTargetsEffect().setText("Then those creatures fight each other"));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL));
}
diff --git a/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java b/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java
index 4bac79d4cd7..44b5a6d7b5f 100644
--- a/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java
+++ b/Mage.Sets/src/mage/cards/l/LuxaRiverShrine.java
@@ -1,43 +1,39 @@
-
package mage.cards.l;
-import java.util.UUID;
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.TapSourceCost;
-import mage.abilities.costs.mana.ManaCostsImpl;
+import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author jeffwadsworth
*/
public final class LuxaRiverShrine extends CardImpl {
- private static final String rule = "{T}: You gain 2 life. Activate only if there are three or more brick counters on {this}.";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.BRICK, 3);
public LuxaRiverShrine(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {1}, {T}: You gain 1 life. Put a brick counter on Luxa River Shrine.
- Ability ability = new SimpleActivatedAbility(new GainLifeEffect(1), new ManaCostsImpl<>("{1}"));
+ Ability ability = new SimpleActivatedAbility(new GainLifeEffect(1), new GenericManaCost(1));
ability.addCost(new TapSourceCost());
ability.addEffect(new AddCountersSourceEffect(CounterType.BRICK.createInstance()));
this.addAbility(ability);
// {T}: You gain 2 life. Activate this ability only if there are three or more brick counters on Luxa River Shrine.
- Condition condition = new SourceHasCounterCondition(CounterType.BRICK, 3, Integer.MAX_VALUE);
- this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new TapSourceCost(), condition, rule));
-
+ this.addAbility(new ConditionalActivatedAbility(new GainLifeEffect(2), new TapSourceCost(), condition));
}
private LuxaRiverShrine(final LuxaRiverShrine card) {
diff --git a/Mage.Sets/src/mage/cards/l/LyseHext.java b/Mage.Sets/src/mage/cards/l/LyseHext.java
index a86f4394891..a32865238c9 100644
--- a/Mage.Sets/src/mage/cards/l/LyseHext.java
+++ b/Mage.Sets/src/mage/cards/l/LyseHext.java
@@ -20,7 +20,7 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.watchers.common.SpellsCastWatcher;
@@ -31,7 +31,10 @@ import java.util.UUID;
*/
public final class LyseHext extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard("noncreature spells");
+ private static final FilterCard filter = new FilterCard("noncreature spells");
+ static {
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
+ }
public LyseHext(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}");
diff --git a/Mage.Sets/src/mage/cards/m/Malfegor.java b/Mage.Sets/src/mage/cards/m/Malfegor.java
index 350a076c26b..8b81dc09beb 100644
--- a/Mage.Sets/src/mage/cards/m/Malfegor.java
+++ b/Mage.Sets/src/mage/cards/m/Malfegor.java
@@ -1,25 +1,26 @@
package mage.cards.m;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeOpponentsEffect;
-import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.SubType;
import mage.constants.Outcome;
+import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
+import mage.game.Controllable;
import mage.game.Game;
-import mage.players.Player;
+
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
/**
- *
* @author jeffwadsworth
*/
public final class Malfegor extends CardImpl {
@@ -38,7 +39,6 @@ public final class Malfegor extends CardImpl {
// When Malfegor enters the battlefield, discard your hand. Each opponent sacrifices a creature for each card discarded this way.
this.addAbility(new EntersBattlefieldTriggeredAbility(new MalfegorEffect(), false));
-
}
private Malfegor(final Malfegor card) {
@@ -64,16 +64,17 @@ class MalfegorEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- Player controller = game.getPlayer(source.getControllerId());
- if (controller == null) {
- return false;
- }
- int sacrificeNumber = controller.getHand().size();
- if (sacrificeNumber == 0) {
- return true;
- }
- new DiscardHandControllerEffect().apply(game, source);
- return new SacrificeOpponentsEffect(sacrificeNumber, StaticFilters.FILTER_CONTROLLED_CREATURE).apply(game, source);
+ return Optional
+ .ofNullable(source)
+ .map(Controllable::getControllerId)
+ .map(game::getPlayer)
+ .filter(player -> !player.getHand().isEmpty())
+ .map(player -> player.discard(player.getHand(), false, source, game))
+ .map(Set::size)
+ .filter(amount -> amount > 0 && new SacrificeOpponentsEffect(
+ amount, StaticFilters.FILTER_CONTROLLED_CREATURE
+ ).apply(game, source))
+ .isPresent();
}
@Override
diff --git a/Mage.Sets/src/mage/cards/m/ManaBloom.java b/Mage.Sets/src/mage/cards/m/ManaBloom.java
index b3653beb35c..e2aad460227 100644
--- a/Mage.Sets/src/mage/cards/m/ManaBloom.java
+++ b/Mage.Sets/src/mage/cards/m/ManaBloom.java
@@ -1,32 +1,29 @@
-
package mage.cards.m;
-import mage.abilities.Ability;
-import mage.abilities.TriggeredAbility;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
import mage.abilities.mana.LimitedTimesPerTurnActivatedManaAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
import java.util.UUID;
/**
- *
* @author LevelX2
*/
public final class ManaBloom extends CardImpl {
- static final String rule = "with X charge counters on it";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, ComparisonType.EQUAL_TO, 0);
public ManaBloom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{X}{G}");
@@ -35,16 +32,15 @@ public final class ManaBloom extends CardImpl {
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.CHARGE.createInstance())));
// Remove a charge counter from Mana Bloom: Add one mana of any color. Activate this ability only once each turn.
- Ability ability = new LimitedTimesPerTurnActivatedManaAbility(
+ this.addAbility(new LimitedTimesPerTurnActivatedManaAbility(
Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(),
new RemoveCountersSourceCost(CounterType.CHARGE.createInstance())
- );
- this.addAbility(ability);
+ ));
// At the beginning of your upkeep, if Mana Bloom has no charge counters on it, return it to its owner's hand.
- TriggeredAbility triggeredAbility = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true));
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggeredAbility, new SourceHasCounterCondition(CounterType.CHARGE, 0, 0), "At the beginning of your upkeep, if Mana Bloom has no charge counters on it, return it to its owner's hand."));
-
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new ReturnToHandSourceEffect(true).setText("return it to its owner's hand")
+ ).withInterveningIf(condition));
}
private ManaBloom(final ManaBloom card) {
diff --git a/Mage.Sets/src/mage/cards/m/MangarasBlessing.java b/Mage.Sets/src/mage/cards/m/MangarasBlessing.java
index 9fc0f218eaf..9ea2945fb29 100644
--- a/Mage.Sets/src/mage/cards/m/MangarasBlessing.java
+++ b/Mage.Sets/src/mage/cards/m/MangarasBlessing.java
@@ -26,7 +26,7 @@ public final class MangarasBlessing extends CardImpl {
// When a spell or ability an opponent controls causes you to discard Mangara's Blessing,
// you gain 2 life, and you return Mangara's Blessing from your graveyard to your hand at the beginning of the next end step.
- Ability ability = new DiscardedByOpponentTriggeredAbility(new GainLifeEffect(2), true);
+ Ability ability = new DiscardedByOpponentTriggeredAbility(new GainLifeEffect(2));
Effect graveyardReturnNextEndEffect = new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnSourceFromGraveyardToHandEffect()));
diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheWorldOoze.java b/Mage.Sets/src/mage/cards/m/MarchOfTheWorldOoze.java
index 44328e1b21f..2385f48705f 100644
--- a/Mage.Sets/src/mage/cards/m/MarchOfTheWorldOoze.java
+++ b/Mage.Sets/src/mage/cards/m/MarchOfTheWorldOoze.java
@@ -34,11 +34,11 @@ public final class MarchOfTheWorldOoze extends CardImpl {
// Creatures you control have base power and toughness 6/6 and are Oozes in addition to their other types.
Ability ability = new SimpleStaticAbility(new SetBasePowerToughnessAllEffect(
- 6, 6, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURE
+ 6, 6, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES
));
ability.addEffect(new AddCardSubtypeAllEffect(
- StaticFilters.FILTER_CONTROLLED_CREATURE, SubType.OOZE, null
- ).concatBy("and"));
+ StaticFilters.FILTER_CONTROLLED_CREATURES, SubType.OOZE, null
+ ).setText("and are Oozes in addition to their other types"));
this.addAbility(ability);
// Whenever an opponent casts a spell, if it's not their turn, you create a 3/3 green Elephant creature token.
diff --git a/Mage.Sets/src/mage/cards/m/MarketbackWalker.java b/Mage.Sets/src/mage/cards/m/MarketbackWalker.java
index fcca439cd66..79ae7f2372e 100644
--- a/Mage.Sets/src/mage/cards/m/MarketbackWalker.java
+++ b/Mage.Sets/src/mage/cards/m/MarketbackWalker.java
@@ -41,7 +41,7 @@ public final class MarketbackWalker extends CardImpl {
));
// When this creature dies, draw a card for each +1/+1 counter on it.
- this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(xValue)));
+ this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(xValue).setText("draw a card for each +1/+1 counter on it")));
}
private MarketbackWalker(final MarketbackWalker card) {
diff --git a/Mage.Sets/src/mage/cards/m/MarshalsPathcruiser.java b/Mage.Sets/src/mage/cards/m/MarshalsPathcruiser.java
index 86b53670b0d..16a2732dc8c 100644
--- a/Mage.Sets/src/mage/cards/m/MarshalsPathcruiser.java
+++ b/Mage.Sets/src/mage/cards/m/MarshalsPathcruiser.java
@@ -42,7 +42,7 @@ public final class MarshalsPathcruiser extends CardImpl {
new AddCardTypeSourceEffect(Duration.Custom, CardType.ARTIFACT, CardType.CREATURE),
new ManaCostsImpl<>("{W}{U}{B}{R}{G}")
);
- ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)));
+ ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)).setText("Put two +1/+1 counters on it"));
this.addAbility(ability);
// Crew 5
diff --git a/Mage.Sets/src/mage/cards/m/MemoryVampire.java b/Mage.Sets/src/mage/cards/m/MemoryVampire.java
new file mode 100644
index 00000000000..d1925c1c47f
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/m/MemoryVampire.java
@@ -0,0 +1,108 @@
+package mage.cards.m;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
+import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
+import mage.abilities.costs.Cost;
+import mage.abilities.costs.common.CollectEvidenceCost;
+import mage.abilities.dynamicvalue.common.SavedDamageValue;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.MayCastTargetCardEffect;
+import mage.abilities.effects.common.MillCardsTargetEffect;
+import mage.abilities.keyword.FlyingAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.CastManaAdjustment;
+import mage.constants.Outcome;
+import mage.constants.SubType;
+import mage.filter.FilterCard;
+import mage.filter.common.FilterNonlandCard;
+import mage.filter.predicate.card.OwnerIdPredicate;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.TargetPlayer;
+import mage.target.common.TargetCardInGraveyard;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class MemoryVampire extends CardImpl {
+
+ public MemoryVampire(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{B}");
+
+ this.subtype.add(SubType.VAMPIRE);
+ this.subtype.add(SubType.DETECTIVE);
+ this.power = new MageInt(4);
+ this.toughness = new MageInt(4);
+
+ // Flying
+ this.addAbility(FlyingAbility.getInstance());
+
+ // Whenever Memory Vampire deals combat damage to a player, any number of target players each mill that many cards. Then you may collect evidence 9. When you do, you may cast target nonland card from defending player's graveyard without paying its mana cost.
+ Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(
+ new MillCardsTargetEffect(SavedDamageValue.MANY)
+ .setText("any number of target players each mill that many cards")
+ );
+ ability.addEffect(new MemoryVampireEffect());
+ ability.addTarget(new TargetPlayer(0, Integer.MAX_VALUE, false));
+ this.addAbility(ability);
+ }
+
+ private MemoryVampire(final MemoryVampire card) {
+ super(card);
+ }
+
+ @Override
+ public MemoryVampire copy() {
+ return new MemoryVampire(this);
+ }
+}
+
+class MemoryVampireEffect extends OneShotEffect {
+
+ MemoryVampireEffect() {
+ super(Outcome.Benefit);
+ staticText = "Then you may collect evidence 9. When you do, you may cast target " +
+ "nonland card from defending player's graveyard without paying its mana cost";
+ }
+
+ private MemoryVampireEffect(final MemoryVampireEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public MemoryVampireEffect copy() {
+ return new MemoryVampireEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player player = game.getPlayer(source.getControllerId());
+ if (player == null) {
+ return false;
+ }
+ Cost cost = new CollectEvidenceCost(9);
+ if (!cost.canPay(source, source, source.getControllerId(), game)
+ || !player.chooseUse(outcome, "Collect evidence 9?", source, game)
+ || !cost.pay(source, game, source, source.getControllerId(), true)) {
+ return false;
+ }
+ UUID defenderId = (UUID) getValue("damagedPlayer");
+ if (defenderId == null) {
+ return true;
+ }
+ ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
+ new MayCastTargetCardEffect(CastManaAdjustment.WITHOUT_PAYING_MANA_COST), false
+ );
+ FilterCard filter = new FilterNonlandCard("nonland card from defending player's graveyard");
+ filter.add(new OwnerIdPredicate(defenderId));
+ ability.addTarget(new TargetCardInGraveyard(filter));
+ game.fireReflexiveTriggeredAbility(ability, source);
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/m/MendicantCoreGuidelight.java b/Mage.Sets/src/mage/cards/m/MendicantCoreGuidelight.java
index c88230090a1..452594e3917 100644
--- a/Mage.Sets/src/mage/cards/m/MendicantCoreGuidelight.java
+++ b/Mage.Sets/src/mage/cards/m/MendicantCoreGuidelight.java
@@ -16,9 +16,7 @@ import mage.abilities.keyword.StartYourEnginesAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
-import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterArtifactSpell;
import java.util.UUID;
@@ -27,7 +25,6 @@ import java.util.UUID;
*/
public final class MendicantCoreGuidelight extends CardImpl {
- private static final FilterSpell filter = new FilterArtifactSpell("an artifact spell");
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS);
public MendicantCoreGuidelight(UUID ownerId, CardSetInfo setInfo) {
@@ -47,7 +44,7 @@ public final class MendicantCoreGuidelight extends CardImpl {
Effect copyEffect = new CopyTargetStackObjectEffect(true)
.setText("copy it. (The copy becomes a token.)");
Effect doIfEffect = new DoIfCostPaid(copyEffect, new ManaCostsImpl<>("{1}"));
- Ability ability = new SpellCastControllerTriggeredAbility(doIfEffect, filter, false, SetTargetPointer.SPELL);
+ Ability ability = new SpellCastControllerTriggeredAbility(doIfEffect, StaticFilters.FILTER_SPELL_AN_ARTIFACT, false, SetTargetPointer.SPELL);
this.addAbility(new MaxSpeedAbility(ability));
}
diff --git a/Mage.Sets/src/mage/cards/m/Merseine.java b/Mage.Sets/src/mage/cards/m/Merseine.java
index 504e36fc3f1..7dc44d7a816 100644
--- a/Mage.Sets/src/mage/cards/m/Merseine.java
+++ b/Mage.Sets/src/mage/cards/m/Merseine.java
@@ -48,7 +48,7 @@ public final class Merseine extends CardImpl {
// Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(),
- new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it")));
+ new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if {this} has a net counter on it")));
// Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if they control the enchanted creature.
SimpleActivatedAbility ability = new MerseineActivatedAbility();
@@ -95,7 +95,7 @@ class MerseineActivatedAbility extends SimpleActivatedAbility {
@Override
public String getRule() {
- return "Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if they control the enchanted creature.";
+ return "Pay enchanted creature's mana cost: Remove a net counter from {this}. Only the controller of the enchanted creature may activate this ability.";
}
}
diff --git a/Mage.Sets/src/mage/cards/m/Metrognome.java b/Mage.Sets/src/mage/cards/m/Metrognome.java
index 012cb2271c0..4c11c7b397c 100644
--- a/Mage.Sets/src/mage/cards/m/Metrognome.java
+++ b/Mage.Sets/src/mage/cards/m/Metrognome.java
@@ -10,7 +10,6 @@ import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.Zone;
import mage.game.permanent.token.GnomeToken;
/**
@@ -23,7 +22,7 @@ public final class Metrognome extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// When a spell or ability an opponent controls causes you to discard Metrognome, create four 1/1 colorless Gnome artifact creature tokens.
- this.addAbility(new DiscardedByOpponentTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 4), true));
+ this.addAbility(new DiscardedByOpponentTriggeredAbility(new CreateTokenEffect(new GnomeToken(), 4)));
// {4}, {tap}: Create a 1/1 colorless Gnome artifact creature token.
Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new GnomeToken()), new ManaCostsImpl<>("{4}"));
diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java
index 93b35e1a10f..728f9cff566 100644
--- a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java
+++ b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java
@@ -116,7 +116,7 @@ class MirrorOfFateTarget extends TargetCardInExile {
&& game.getState().getZone(card.getId()) == Zone.EXILED) {
for (ExileZone exile : game.getExile().getExileZones()) {
if (exile != null && exile.contains(id)) {
- return filter.match(card, source.getControllerId(), game);
+ return filter.match(card, source.getControllerId(), source, game);
}
}
}
diff --git a/Mage.Sets/src/mage/cards/m/MishrasWorkshop.java b/Mage.Sets/src/mage/cards/m/MishrasWorkshop.java
index 907f02c9c13..4ab48ee0610 100644
--- a/Mage.Sets/src/mage/cards/m/MishrasWorkshop.java
+++ b/Mage.Sets/src/mage/cards/m/MishrasWorkshop.java
@@ -1,4 +1,3 @@
-
package mage.cards.m;
import java.util.UUID;
@@ -8,7 +7,7 @@ import mage.abilities.mana.conditional.ConditionalSpellManaBuilder;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.filter.common.FilterArtifactSpell;
+import mage.filter.FilterSpell;
/**
*
@@ -16,12 +15,17 @@ import mage.filter.common.FilterArtifactSpell;
*/
public final class MishrasWorkshop extends CardImpl {
+ private static final FilterSpell filter = new FilterSpell("artifact spells");
+ static {
+ filter.add(CardType.ARTIFACT.getPredicate());
+ }
+
public MishrasWorkshop(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
// {tap}: Add {C}{C}{C}. Spend this mana only to cast artifact spells.
this.addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 3,
- new ConditionalSpellManaBuilder(new FilterArtifactSpell("artifact spells"))));
+ new ConditionalSpellManaBuilder(filter)));
}
diff --git a/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java b/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java
index 304042e182e..9959e14301a 100644
--- a/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java
+++ b/Mage.Sets/src/mage/cards/m/MistbladeShinobi.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -38,7 +38,7 @@ public final class MistbladeShinobi extends CardImpl {
// Whenever Mistblade Shinobi deals combat damage to a player, you may return target creature that player controls to its owner's hand.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandTargetEffect(), true, true);
ability.addTarget(new TargetCreaturePermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java
index 38cf90d99a6..b35b152259b 100644
--- a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java
+++ b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java
@@ -61,7 +61,7 @@ class MogisGodOfSlaughterEffect extends OneShotEffect {
MogisGodOfSlaughterEffect() {
super(Outcome.Damage);
- staticText = "{this} deals 2 damage to that player unless they sacrifice a creature";
+ staticText = "{this} deals 2 damage to that player unless they sacrifice a creature of their choice";
}
private MogisGodOfSlaughterEffect(final MogisGodOfSlaughterEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/m/MoiraAndTeshar.java b/Mage.Sets/src/mage/cards/m/MoiraAndTeshar.java
index 2abe1bb1625..7af8132d513 100644
--- a/Mage.Sets/src/mage/cards/m/MoiraAndTeshar.java
+++ b/Mage.Sets/src/mage/cards/m/MoiraAndTeshar.java
@@ -16,8 +16,7 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import mage.filter.common.FilterPermanentCard;
import mage.game.Game;
import mage.game.permanent.Permanent;
@@ -30,7 +29,6 @@ import java.util.UUID;
public final class MoiraAndTeshar extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
private static final FilterPermanentCard targetFilter = new FilterPermanentCard(
"nonland permanent card from your graveyard");
@@ -51,7 +49,7 @@ public final class MoiraAndTeshar extends CardImpl {
// Whenever you cast a historic spell, return target nonland permanent card from
// your graveyard to the battlefield. It gains haste. Exile it at the beginning
// of the next end step.
- Ability ability = new SpellCastControllerTriggeredAbility(new MoiraAndTesharEffect(), filter, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new MoiraAndTesharEffect(), StaticFilters.FILTER_SPELL_HISTORIC, false);
ability.addTarget(new TargetCardInYourGraveyard(targetFilter));
// If it would leave the battlefield, exile it instead of putting it anywhere
diff --git a/Mage.Sets/src/mage/cards/m/MonasteryMessenger.java b/Mage.Sets/src/mage/cards/m/MonasteryMessenger.java
index cf0872e16b9..f4fecac108f 100644
--- a/Mage.Sets/src/mage/cards/m/MonasteryMessenger.java
+++ b/Mage.Sets/src/mage/cards/m/MonasteryMessenger.java
@@ -11,7 +11,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInYourGraveyard;
@@ -22,10 +22,10 @@ import java.util.UUID;
*/
public final class MonasteryMessenger extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard("noncreature, nonland card from your graveyard");
+ private static final FilterCard filter = new FilterNonlandCard("noncreature, nonland card from your graveyard");
static {
- filter.add(Predicates.not(CardType.LAND.getPredicate()));
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
}
public MonasteryMessenger(UUID ownerId, CardSetInfo setInfo) {
diff --git a/Mage.Sets/src/mage/cards/m/MordantDragon.java b/Mage.Sets/src/mage/cards/m/MordantDragon.java
index d336d6a8a2f..634fc2d91ec 100644
--- a/Mage.Sets/src/mage/cards/m/MordantDragon.java
+++ b/Mage.Sets/src/mage/cards/m/MordantDragon.java
@@ -15,9 +15,8 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
-import mage.constants.Zone;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -45,7 +44,7 @@ public final class MordantDragon extends CardImpl {
effect.setText("have it deal that much damage to target creature that player controls.");
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, true, true);
ability.addTarget(new TargetCreaturePermanent());
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/m/MuseVessel.java b/Mage.Sets/src/mage/cards/m/MuseVessel.java
index 5107bc656c9..04a1518e5e6 100644
--- a/Mage.Sets/src/mage/cards/m/MuseVessel.java
+++ b/Mage.Sets/src/mage/cards/m/MuseVessel.java
@@ -154,9 +154,7 @@ class TargetCardInMuseVesselExile extends TargetCardInExile {
if (sourceCard != null) {
UUID exileId = CardUtil.getCardExileZoneId(game, source.getSourceId());
ExileZone exile = game.getExile().getExileZone(exileId);
- if (exile != null && !exile.isEmpty()) {
- return true;
- }
+ return exile != null && !exile.isEmpty();
}
return false;
}
@@ -172,7 +170,7 @@ class TargetCardInMuseVesselExile extends TargetCardInExile {
exile = game.getExile().getExileZone(exileId);
}
if (exile != null && exile.contains(id)) {
- return filter.match(card, source.getControllerId(), game);
+ return filter.match(card, source.getControllerId(), source, game);
}
}
return false;
diff --git a/Mage.Sets/src/mage/cards/n/NabanDeanOfIteration.java b/Mage.Sets/src/mage/cards/n/NabanDeanOfIteration.java
index 4f2707720d2..8061511e12c 100644
--- a/Mage.Sets/src/mage/cards/n/NabanDeanOfIteration.java
+++ b/Mage.Sets/src/mage/cards/n/NabanDeanOfIteration.java
@@ -52,7 +52,7 @@ class NabanDeanOfIterationEffect extends ReplacementEffectImpl {
NabanDeanOfIterationEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = "If a Wizard entering under your control causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time";
+ staticText = "if a Wizard you control entering causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time";
}
private NabanDeanOfIterationEffect(final NabanDeanOfIterationEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java b/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java
index 695aa58165a..a4db3dfc9be 100644
--- a/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java
+++ b/Mage.Sets/src/mage/cards/n/NeglectedHeirloom.java
@@ -1,8 +1,5 @@
-
package mage.cards.n;
-import java.util.UUID;
-
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
@@ -13,13 +10,15 @@ import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.SubType;
import mage.constants.Outcome;
+import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.target.common.TargetControlledCreaturePermanent;
+import java.util.UUID;
+
/**
* @author halljared
*/
@@ -85,6 +84,6 @@ class NeglectedHeirloomTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
- return "When equipped creature transforms, transform Neglected Heirloom.";
+ return "When equipped creature transforms, transform {this}.";
}
}
diff --git a/Mage.Sets/src/mage/cards/n/NikkoOnna.java b/Mage.Sets/src/mage/cards/n/NikkoOnna.java
index 0db75a430b1..67a6bbf9035 100644
--- a/Mage.Sets/src/mage/cards/n/NikkoOnna.java
+++ b/Mage.Sets/src/mage/cards/n/NikkoOnna.java
@@ -33,7 +33,7 @@ public final class NikkoOnna extends CardImpl {
this.addAbility(ability);
// Whenever you cast a Spirit or Arcane spell, you may return Nikko-Onna to its owner's hand.
- this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private NikkoOnna(final NikkoOnna card) {
diff --git a/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java b/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java
index 931831c102e..3422ccb86fc 100644
--- a/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java
+++ b/Mage.Sets/src/mage/cards/n/NikoLightOfHope.java
@@ -74,7 +74,7 @@ class NikoLightOfHopeEffect extends OneShotEffect {
NikoLightOfHopeEffect() {
super(Outcome.Benefit);
- staticText = "Exile target nonlegendary creature you control. Shards you control become copies of it until the beginning of the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step.";
+ staticText = "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.";
}
private NikoLightOfHopeEffect(final NikoLightOfHopeEffect effect) {
@@ -112,4 +112,4 @@ class NikoLightOfHopeEffect extends OneShotEffect {
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java
index 62083b226ff..a442e7c1431 100644
--- a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java
+++ b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java
@@ -74,11 +74,7 @@ class NissasEncouragementEffect extends OneShotEffect {
NissasEncouragementTarget target = new NissasEncouragementTarget(filter);
if (player.searchLibrary(target, source, game)) {
- boolean searchGY = false;
-
- if (target.getTargets().size() < 3) {
- searchGY = true;
- }
+ boolean searchGY = target.getTargets().size() < 3;
Map foundCards = new HashMap<>();
foundCards.put("Forest", 0);
@@ -154,7 +150,7 @@ class NissasEncouragementTarget extends TargetCardInLibrary {
return false;
}
}
- return filter.match(card, playerId, game);
+ return filter.match(card, playerId, source, game);
}
return false;
}
diff --git a/Mage.Sets/src/mage/cards/o/OraclesVault.java b/Mage.Sets/src/mage/cards/o/OraclesVault.java
index 94b7f095643..9ddbc215f7c 100644
--- a/Mage.Sets/src/mage/cards/o/OraclesVault.java
+++ b/Mage.Sets/src/mage/cards/o/OraclesVault.java
@@ -2,18 +2,21 @@ package mage.cards.o;
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.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalActivatedAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect;
import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
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.TargetController;
import mage.counters.CounterType;
import mage.game.Game;
import mage.players.Player;
@@ -25,25 +28,21 @@ import java.util.UUID;
*/
public final class OraclesVault extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.BRICK, 3);
+
public OraclesVault(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
- // {2}, {T}: Exile the top card of your library. Until end of turn, you may play that card.
+ // {2}, {T}: Exile the top card of your library. Until end of turn, you may play that card. Put a brick counter on Oracle's Vault.
Ability ability = new SimpleActivatedAbility(new ExileTopXMayPlayUntilEffect(1, Duration.EndOfTurn)
.withTextOptions("that card", false), new GenericManaCost(2));
ability.addCost(new TapSourceCost());
-
- // Put a brick counter on Oracle's Vault.
- Effect effect2 = new AddCountersSourceEffect(CounterType.BRICK.createInstance());
- ability.addEffect(effect2);
+ ability.addEffect(new AddCountersSourceEffect(CounterType.BRICK.createInstance()));
this.addAbility(ability);
// {T}: Exile the top card of your library. Until end of turn, you may play that card without paying its mana cost.
// Activate this ability only if there are three or more brick counters on Oracle's Vault.
- this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD,
- new OraclesVaultFreeEffect(), new TapSourceCost(), new SourceHasCounterCondition(CounterType.BRICK, 3, Integer.MAX_VALUE),
- "{T}: Exile the top card of your library. Until end of turn, you may play that card without paying its mana cost. "
- + "Activate only if there are three or more brick counters on {this}."));
+ this.addAbility(new ConditionalActivatedAbility(new OraclesVaultFreeEffect(), new TapSourceCost(), condition));
}
private OraclesVault(final OraclesVault card) {
@@ -60,6 +59,7 @@ class OraclesVaultFreeEffect extends OneShotEffect {
OraclesVaultFreeEffect() {
super(Outcome.Benefit);
+ staticText = "exile the top card of your library. Until end of turn, you may play that card without paying its mana cost";
}
private OraclesVaultFreeEffect(final OraclesVaultFreeEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/o/OranRiefTheVastwood.java b/Mage.Sets/src/mage/cards/o/OranRiefTheVastwood.java
index b86bbdcebf4..c2f65f93180 100644
--- a/Mage.Sets/src/mage/cards/o/OranRiefTheVastwood.java
+++ b/Mage.Sets/src/mage/cards/o/OranRiefTheVastwood.java
@@ -1,37 +1,40 @@
-
-
package mage.cards.o;
-import java.util.UUID;
import mage.ObjectColor;
-import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
-import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.mana.GreenManaAbility;
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.FilterPermanent;
+import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
+import mage.filter.predicate.permanent.EnteredThisTurnPredicate;
+
+import java.util.UUID;
/**
- *
* @author BetaSteward_at_googlemail.com
*/
public final class OranRiefTheVastwood extends CardImpl {
+ private static final FilterPermanent filter = new FilterCreaturePermanent("green creature that entered this turn");
+
+ static {
+ filter.add(new ColorPredicate(ObjectColor.GREEN));
+ filter.add(EnteredThisTurnPredicate.instance);
+ }
+
public OranRiefTheVastwood(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
+
this.addAbility(new EntersBattlefieldTappedAbility());
this.addAbility(new GreenManaAbility());
- this.addAbility(new SimpleActivatedAbility(new OranRiefTheVastwoodEffect(), new TapSourceCost()));
+ this.addAbility(new SimpleActivatedAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), new TapSourceCost()));
}
private OranRiefTheVastwood(final OranRiefTheVastwood card) {
@@ -42,36 +45,4 @@ public final class OranRiefTheVastwood extends CardImpl {
public OranRiefTheVastwood copy() {
return new OranRiefTheVastwood(this);
}
-
-}
-
-class OranRiefTheVastwoodEffect extends OneShotEffect {
-
- OranRiefTheVastwoodEffect() {
- super(Outcome.BoostCreature);
- staticText = "Put a +1/+1 counter on each green creature that entered the battlefield this turn";
- }
-
- private OranRiefTheVastwoodEffect(final OranRiefTheVastwoodEffect effect) {
- super(effect);
- }
-
- @Override
- public OranRiefTheVastwoodEffect copy() {
- return new OranRiefTheVastwoodEffect(this);
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- FilterPermanent filter = new FilterPermanent();
- filter.add(CardType.CREATURE.getPredicate());
- filter.add(new ColorPredicate(ObjectColor.GREEN));
- for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) {
- if (permanent.getTurnsOnBattlefield() == 0) {
- permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game);
- }
- }
- return true;
- }
-
}
diff --git a/Mage.Sets/src/mage/cards/o/OrbweaverKumo.java b/Mage.Sets/src/mage/cards/o/OrbweaverKumo.java
index 0fbaddcd627..5a700426460 100644
--- a/Mage.Sets/src/mage/cards/o/OrbweaverKumo.java
+++ b/Mage.Sets/src/mage/cards/o/OrbweaverKumo.java
@@ -27,7 +27,7 @@ public final class OrbweaverKumo extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(4);
this.addAbility(ReachAbility.getInstance());
- this.addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect(new ForestwalkAbility(), Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new GainAbilitySourceEffect(new ForestwalkAbility(), Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private OrbweaverKumo(final OrbweaverKumo card) {
diff --git a/Mage.Sets/src/mage/cards/o/OrdruunMentor.java b/Mage.Sets/src/mage/cards/o/OrdruunMentor.java
new file mode 100644
index 00000000000..a42c25b507a
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/o/OrdruunMentor.java
@@ -0,0 +1,104 @@
+package mage.cards.o;
+
+import mage.MageInt;
+import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
+import mage.abilities.keyword.FirstStrikeAbility;
+import mage.abilities.keyword.MentorAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.SubType;
+import mage.constants.Zone;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterCreaturePermanent;
+import mage.filter.predicate.ObjectSourcePlayer;
+import mage.filter.predicate.ObjectSourcePlayerPredicate;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+import mage.target.TargetPermanent;
+import mage.util.CardUtil;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class OrdruunMentor extends CardImpl {
+
+ public OrdruunMentor(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/W}");
+
+ this.subtype.add(SubType.MINOTAUR);
+ this.subtype.add(SubType.SOLDIER);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(2);
+
+ // Mentor
+ this.addAbility(new MentorAbility());
+
+ // Whenever you attack a player, target creature that's attacking that player gains first strike until end of turn.
+ this.addAbility(new OrdruunMentorTriggeredAbility());
+ }
+
+ private OrdruunMentor(final OrdruunMentor card) {
+ super(card);
+ }
+
+ @Override
+ public OrdruunMentor copy() {
+ return new OrdruunMentor(this);
+ }
+}
+
+class OrdruunMentorTriggeredAbility extends TriggeredAbilityImpl {
+
+ private enum OrdruunMentorPredicate implements ObjectSourcePlayerPredicate {
+ instance;
+
+ @Override
+ public boolean apply(ObjectSourcePlayer input, Game game) {
+ return CardUtil.getEffectValueFromAbility(
+ input.getSource(), "playerAttacked", UUID.class
+ )
+ .filter(uuid -> uuid.equals(game.getCombat().getDefenderId(input.getObject().getId())))
+ .isPresent();
+ }
+ }
+
+ private static final FilterPermanent filter = new FilterCreaturePermanent("creature that's attacking that player");
+
+ static {
+ filter.add(OrdruunMentorPredicate.instance);
+ }
+
+ OrdruunMentorTriggeredAbility() {
+ super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()).setText(""));
+ this.setTriggerPhrase("Whenever you attack a player, ");
+ this.addTarget(new TargetPermanent(filter));
+ }
+
+ private OrdruunMentorTriggeredAbility(final OrdruunMentorTriggeredAbility ability) {
+ super(ability);
+ }
+
+ @Override
+ public OrdruunMentorTriggeredAbility copy() {
+ return new OrdruunMentorTriggeredAbility(this);
+ }
+
+ @Override
+ public boolean checkEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED;
+ }
+
+ @Override
+ public boolean checkTrigger(GameEvent event, Game game) {
+ if (!isControlledBy(event.getPlayerId()) || game.getPlayer(event.getTargetId()) == null) {
+ return false;
+ }
+ this.getEffects().setValue("playerAttacked", event.getTargetId());
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/o/OreGorger.java b/Mage.Sets/src/mage/cards/o/OreGorger.java
index 19a5014d5df..b593719d0ff 100644
--- a/Mage.Sets/src/mage/cards/o/OreGorger.java
+++ b/Mage.Sets/src/mage/cards/o/OreGorger.java
@@ -25,7 +25,7 @@ public final class OreGorger extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(1);
- Ability ability = new SpellCastControllerTriggeredAbility(new DestroyTargetEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true);
+ Ability ability = new SpellCastControllerTriggeredAbility(new DestroyTargetEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true);
ability.addTarget(new TargetNonBasicLandPermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/o/OyobiWhoSplitTheHeavens.java b/Mage.Sets/src/mage/cards/o/OyobiWhoSplitTheHeavens.java
index ddfb7efc877..2840bfb6b6f 100644
--- a/Mage.Sets/src/mage/cards/o/OyobiWhoSplitTheHeavens.java
+++ b/Mage.Sets/src/mage/cards/o/OyobiWhoSplitTheHeavens.java
@@ -29,7 +29,7 @@ public final class OyobiWhoSplitTheHeavens extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast a Spirit or Arcane spell, create a 3/3 white Spirit creature token with flying.
- this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new AnotherSpiritToken()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new AnotherSpiritToken()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private OyobiWhoSplitTheHeavens(final OyobiWhoSplitTheHeavens card) {
diff --git a/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java b/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java
index e9e39dc8b95..d7b4ed5f466 100644
--- a/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java
+++ b/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java
@@ -1,18 +1,28 @@
package mage.cards.p;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
+import mage.MageObject;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.condition.common.ControlsPermanentGreatestCMCCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
+import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
+import mage.abilities.hint.ConditionHint;
+import mage.abilities.hint.Hint;
import mage.abilities.keyword.HexproofAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.constants.SuperType;
+import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
+import mage.filter.common.FilterControlledArtifactPermanent;
+import mage.filter.predicate.Predicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
import java.util.UUID;
@@ -21,8 +31,16 @@ import java.util.UUID;
*/
public final class PadeemConsulOfInnovation extends CardImpl {
- private static final Condition condition
- = new ControlsPermanentGreatestCMCCondition(StaticFilters.FILTER_PERMANENT_ARTIFACT);
+ private static final FilterPermanent filter = new FilterControlledArtifactPermanent(
+ "you control the artifact with the greatest mana value or tied for the greatest mana value"
+ );
+
+ static {
+ filter.add(PadeemConsulOfInnovationPredicate.instance);
+ }
+
+ private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter);
+ private static final Hint hint = new ConditionHint(condition);
public PadeemConsulOfInnovation(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
@@ -39,12 +57,7 @@ public final class PadeemConsulOfInnovation extends CardImpl {
)));
// At the beginning of your upkeep, if you control the artifact with the highest converted mana cost or tied for the highest converted mana cost, draw a card.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(
- new DrawCardSourceControllerEffect(1), false
- ), condition, "At the beginning of your upkeep, if you control the artifact " +
- "with the highest mana value or tied for the highest mana value, draw a card."
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1)).withInterveningIf(condition).addHint(hint));
}
private PadeemConsulOfInnovation(final PadeemConsulOfInnovation card) {
@@ -56,3 +69,18 @@ public final class PadeemConsulOfInnovation extends CardImpl {
return new PadeemConsulOfInnovation(this);
}
}
+
+enum PadeemConsulOfInnovationPredicate implements Predicate {
+ instance;
+
+ @Override
+ public boolean apply(Permanent input, Game game) {
+ return input.getManaValue() >= game
+ .getBattlefield()
+ .getActivePermanents(StaticFilters.FILTER_PERMANENT_ARTIFACT, input.getControllerId(), game)
+ .stream()
+ .mapToInt(MageObject::getManaValue)
+ .max()
+ .orElse(-1);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java b/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java
index 52a3f52255f..5a650a1ec43 100644
--- a/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java
+++ b/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java
@@ -1,13 +1,8 @@
package mage.cards.p;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
import mage.MageInt;
-import mage.MageObjectReference;
-import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
-import mage.abilities.condition.Condition;
+import mage.abilities.condition.common.SourceHasntDealtDamageThisGameCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlyingAbility;
@@ -19,15 +14,11 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.constants.WatcherScope;
-import mage.constants.Zone;
-import mage.game.Game;
-import mage.game.events.GameEvent;
-import mage.game.permanent.Permanent;
-import mage.watchers.Watcher;
+import mage.watchers.common.DealtDamageThisGameWatcher;
+
+import java.util.UUID;
/**
- *
* @author TheElk801
*/
public final class PalladiaMorsTheRuiner extends CardImpl {
@@ -51,13 +42,11 @@ public final class PalladiaMorsTheRuiner extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Palladia-Mors, the Ruiner has hexproof if it hasn't dealt damage yet.
- this.addAbility(new SimpleStaticAbility(
- new ConditionalContinuousEffect(
- new GainAbilitySourceEffect(HexproofAbility.getInstance()),
- PalladiaMorsTheRuinerCondition.instance,
- "{this} has hexproof if it hasn't dealt damage yet"
- )
- ), new PalladiaMorsTheRuinerWatcher());
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
+ new GainAbilitySourceEffect(HexproofAbility.getInstance()),
+ SourceHasntDealtDamageThisGameCondition.instance,
+ "{this} has hexproof if it hasn't dealt damage yet"
+ )).addHint(SourceHasntDealtDamageThisGameCondition.getHint()), new DealtDamageThisGameWatcher());
}
private PalladiaMorsTheRuiner(final PalladiaMorsTheRuiner card) {
@@ -69,49 +58,3 @@ public final class PalladiaMorsTheRuiner extends CardImpl {
return new PalladiaMorsTheRuiner(this);
}
}
-
-enum PalladiaMorsTheRuinerCondition implements Condition {
-
- instance;
-
- @Override
- public boolean apply(Game game, Ability source) {
- Permanent permanent = game.getPermanent(source.getSourceId());
- PalladiaMorsTheRuinerWatcher watcher = game.getState().getWatcher(PalladiaMorsTheRuinerWatcher.class);
- return permanent != null && !watcher.getDamagers().contains(new MageObjectReference(permanent, game));
- }
-
- @Override
- public String toString() {
- return "{this} hasn't dealt damage yet";
- }
-
-}
-
-class PalladiaMorsTheRuinerWatcher extends Watcher {
-
- private final Set damagers = new HashSet<>();
-
- public PalladiaMorsTheRuinerWatcher() {
- super(WatcherScope.GAME);
- }
-
- @Override
- public void watch(GameEvent event, Game game) {
- switch (event.getType()) {
- case DAMAGED_PERMANENT:
- case DAMAGED_PLAYER:
- break;
- default:
- return;
- }
- Permanent permanent = game.getPermanent(event.getSourceId());
- if (permanent != null) {
- damagers.add(new MageObjectReference(permanent, game));
- }
- }
-
- public Set getDamagers() {
- return damagers;
- }
-}
diff --git a/Mage.Sets/src/mage/cards/p/Panharmonicon.java b/Mage.Sets/src/mage/cards/p/Panharmonicon.java
index 239825fbfaa..5d9f0a9aebd 100644
--- a/Mage.Sets/src/mage/cards/p/Panharmonicon.java
+++ b/Mage.Sets/src/mage/cards/p/Panharmonicon.java
@@ -43,7 +43,7 @@ class PanharmoniconEffect extends ReplacementEffectImpl {
PanharmoniconEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
- staticText = "If an artifact or creature entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time";
+ staticText = "If an artifact or creature entering causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time";
}
private PanharmoniconEffect(final PanharmoniconEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/p/ParapetThrasher.java b/Mage.Sets/src/mage/cards/p/ParapetThrasher.java
index 8fe9ba4b29e..48725cea523 100644
--- a/Mage.Sets/src/mage/cards/p/ParapetThrasher.java
+++ b/Mage.Sets/src/mage/cards/p/ParapetThrasher.java
@@ -22,7 +22,7 @@ import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
/**
*
@@ -49,7 +49,7 @@ public final class ParapetThrasher extends CardImpl {
filter, true, true, SetTargetPointer.PLAYER, false)
.setTriggerPhrase("Whenever one or more Dragons you control deal combat damage to an opponent, ");
ability.addTarget(new TargetPermanent(artifactFilter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
ability.setModeTag("destroy artifact");
ability.getModes().setLimitUsageByOnce(true);
diff --git a/Mage.Sets/src/mage/cards/p/PartingGust.java b/Mage.Sets/src/mage/cards/p/PartingGust.java
index 6dc25b06a9e..4d7fbfeb5d7 100644
--- a/Mage.Sets/src/mage/cards/p/PartingGust.java
+++ b/Mage.Sets/src/mage/cards/p/PartingGust.java
@@ -36,6 +36,7 @@ import java.util.stream.Collectors;
public final class PartingGust extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature");
+
static {
filter.add(TokenPredicate.FALSE);
}
@@ -52,7 +53,7 @@ public final class PartingGust extends CardImpl {
new ExileTargetEffect(),
new PartingGustExileReturnEffect(),
GiftWasPromisedCondition.TRUE,
- "Exile target nontoken creature. If the gift wasn't promised, return that creature to the " +
+ "Exile target nontoken creature. If the gift wasn't promised, return that card to the " +
"battlefield under its owner's control with a +1/+1 counter on it at the beginning of the next end step."
));
}
diff --git a/Mage.Sets/src/mage/cards/p/PeatBog.java b/Mage.Sets/src/mage/cards/p/PeatBog.java
index efcfde01a27..7607eef1477 100644
--- a/Mage.Sets/src/mage/cards/p/PeatBog.java
+++ b/Mage.Sets/src/mage/cards/p/PeatBog.java
@@ -1,11 +1,10 @@
package mage.cards.p;
-import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.common.EntersBattlefieldTappedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -17,17 +16,21 @@ import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class PeatBog extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, ComparisonType.EQUAL_TO, 0);
+
public PeatBog(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Peat Bog enters the battlefield tapped with two depletion counters on it.
Ability etbAbility = new EntersBattlefieldAbility(
@@ -35,11 +38,15 @@ public final class PeatBog extends CardImpl {
);
etbAbility.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance(2)));
this.addAbility(etbAbility);
+
// {T}, Remove a depletion counter from Peat Bog: Add {B}{B}. If there are no depletion counters on Peat Bog, sacrifice it.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(2), new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.DEPLETION.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.DEPLETION, 0,0), "If there are no depletion counters on {this}, sacrifice it"));
- this.addAbility(ability);
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no depletion counters on {this}, sacrifice it"
+ ));
+ this.addAbility(ability);
}
private PeatBog(final PeatBog card) {
diff --git a/Mage.Sets/src/mage/cards/p/PeerlessRecycling.java b/Mage.Sets/src/mage/cards/p/PeerlessRecycling.java
index 55f023fd46f..bdc60ef9894 100644
--- a/Mage.Sets/src/mage/cards/p/PeerlessRecycling.java
+++ b/Mage.Sets/src/mage/cards/p/PeerlessRecycling.java
@@ -26,7 +26,7 @@ public final class PeerlessRecycling extends CardImpl {
// Return target permanent from your graveyard to your hand. If the gift was promised, instead return two target permanent cards from your graveyard to your hand.
this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()
- .setText("return target permanent from your graveyard to your hand. If the gift was promised, " +
+ .setText("return target permanent card from your graveyard to your hand. If the gift was promised, " +
"instead return two target permanent cards from your graveyard to your hand"));
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_PERMANENT));
this.getSpellAbility().setTargetAdjuster(new ConditionalTargetAdjuster(GiftWasPromisedCondition.TRUE,
diff --git a/Mage.Sets/src/mage/cards/p/PeltCollector.java b/Mage.Sets/src/mage/cards/p/PeltCollector.java
index 848dd821458..86a8f70d3ea 100644
--- a/Mage.Sets/src/mage/cards/p/PeltCollector.java
+++ b/Mage.Sets/src/mage/cards/p/PeltCollector.java
@@ -111,7 +111,7 @@ class PeltCollectorTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
- return "Whenever another creature you control enters the battlefield "
+ return "Whenever another creature you control enters "
+ "or dies, if that creature's power is greater than {this}'s, "
+ "put a +1/+1 counter on {this}.";
}
diff --git a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java
index 4f75542a530..456de66e613 100644
--- a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java
+++ b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java
@@ -31,7 +31,7 @@ public final class PetalmaneBaku extends CardImpl {
this.toughness = new MageInt(2);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Petalmane Baku.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {1}, Remove X ki counters from Petalmane Baku: Add X mana of any one color.
Ability ability = new DynamicManaAbility(
diff --git a/Mage.Sets/src/mage/cards/p/PheliaExuberantShepherd.java b/Mage.Sets/src/mage/cards/p/PheliaExuberantShepherd.java
index 63f6fdba3df..851b8af4e35 100644
--- a/Mage.Sets/src/mage/cards/p/PheliaExuberantShepherd.java
+++ b/Mage.Sets/src/mage/cards/p/PheliaExuberantShepherd.java
@@ -1,6 +1,7 @@
package mage.cards.p;
import mage.MageInt;
+import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
@@ -49,10 +50,7 @@ public final class PheliaExuberantShepherd extends CardImpl {
this.addAbility(FlashAbility.getInstance());
// Whenever Phelia, Exuberant Shepherd attacks, exile up to one other target nonland permanent. At the beginning of the next end step, return that card to the battlefield under its owner's control. If it entered under your control, put a +1/+1 counter on Phelia.
- Ability ability = new AttacksTriggeredAbility(new ExileTargetEffect().setToSourceExileZone(true));
- ability.addEffect(new CreateDelayedTriggeredAbilityEffect(
- new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new PheliaExuberantShepherdEffect()), false
- ));
+ Ability ability = new AttacksTriggeredAbility(new PheliaExuberantShepherdExileEffect());
ability.addTarget(new TargetPermanent(0, 1, filter));
this.addAbility(ability);
}
@@ -67,16 +65,55 @@ public final class PheliaExuberantShepherd extends CardImpl {
}
}
+class PheliaExuberantShepherdExileEffect extends ExileTargetEffect {
+
+ PheliaExuberantShepherdExileEffect() {
+ super();
+ outcome = Outcome.Neutral; // quite contextual outcome.
+ staticText = "exile up to one other target nonland permanent. At the beginning of the next end step, "
+ + "return that card to the battlefield under its owner's control. If it entered under your control, "
+ + "put a +1/+1 counter on {this}.";
+ }
+
+ private PheliaExuberantShepherdExileEffect(final PheliaExuberantShepherdExileEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public PheliaExuberantShepherdExileEffect copy() {
+ return new PheliaExuberantShepherdExileEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ MageObject sourceObject = source.getSourceObject(game);
+ this.exileId = UUID.randomUUID();
+ this.exileZone = sourceObject == null ? null : sourceObject.getIdName();
+ // attempting to exile to the fresh exileId
+ boolean didSomething = super.apply(game, source);
+ // delayed trigger is created even if exiling failed.
+ didSomething |= new CreateDelayedTriggeredAbilityEffect(
+ new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
+ new PheliaExuberantShepherdEffect(this.exileId)), false
+ ).apply(game, source);
+ return didSomething;
+ }
+}
+
class PheliaExuberantShepherdEffect extends OneShotEffect {
- PheliaExuberantShepherdEffect() {
+ private final UUID zoneId; // the exile zone's id for cards to return.
+
+ PheliaExuberantShepherdEffect(UUID zoneId) {
super(Outcome.Benefit);
staticText = "return that card to the battlefield under its owner's control. "
+ "If it entered under your control, put a +1/+1 counter on {this}";
+ this.zoneId = zoneId;
}
private PheliaExuberantShepherdEffect(final PheliaExuberantShepherdEffect effect) {
super(effect);
+ this.zoneId = effect.zoneId;
}
@Override
@@ -90,7 +127,6 @@ class PheliaExuberantShepherdEffect extends OneShotEffect {
if (player == null) {
return false;
}
- UUID zoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
ExileZone exileZone = game.getExile().getExileZone(zoneId);
if (exileZone == null || exileZone.isEmpty()) {
return false;
diff --git a/Mage.Sets/src/mage/cards/p/PiaNalaarChiefMechanic.java b/Mage.Sets/src/mage/cards/p/PiaNalaarChiefMechanic.java
index 59f4a8d8b49..f52834a4cc9 100644
--- a/Mage.Sets/src/mage/cards/p/PiaNalaarChiefMechanic.java
+++ b/Mage.Sets/src/mage/cards/p/PiaNalaarChiefMechanic.java
@@ -1,6 +1,5 @@
package mage.cards.p;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility;
@@ -9,9 +8,9 @@ import mage.abilities.costs.common.PayEnergyCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
-import mage.constants.*;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
+import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
@@ -19,8 +18,9 @@ import mage.game.permanent.token.NalaarAetherjetToken;
import mage.game.permanent.token.Token;
import mage.players.Player;
+import java.util.UUID;
+
/**
- *
* @author Jmlundeen
*/
public final class PiaNalaarChiefMechanic extends CardImpl {
@@ -33,7 +33,7 @@ public final class PiaNalaarChiefMechanic extends CardImpl {
public PiaNalaarChiefMechanic(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}{R}");
-
+
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ARTIFICER);
@@ -64,7 +64,7 @@ class PiaNalaarChiefMechanicEffect extends OneShotEffect {
public PiaNalaarChiefMechanicEffect() {
super(Outcome.Benefit);
staticText = "you may pay one or more {E}. If you do, create an X/X colorless Vehicle artifact token " +
- "named Nalaar Aetherjet with flying and crew 2, where X is the amount of {E} spent this way";
+ "named Nalaar Aetherjet with flying and crew 2, where X is the amount of {E} paid this way";
}
public PiaNalaarChiefMechanicEffect(final PiaNalaarChiefMechanicEffect effect) {
@@ -95,4 +95,4 @@ class PiaNalaarChiefMechanicEffect extends OneShotEffect {
}
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/p/PiaNalaarConsulOfRevival.java b/Mage.Sets/src/mage/cards/p/PiaNalaarConsulOfRevival.java
index d1afbbf6bb9..d1d824a73c4 100644
--- a/Mage.Sets/src/mage/cards/p/PiaNalaarConsulOfRevival.java
+++ b/Mage.Sets/src/mage/cards/p/PiaNalaarConsulOfRevival.java
@@ -1,17 +1,18 @@
package mage.cards.p;
import mage.MageInt;
-import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.PlayLandOrCastSpellFromExileTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
+import mage.constants.SuperType;
import mage.filter.FilterPermanent;
-import mage.game.Game;
-import mage.game.events.GameEvent;
import mage.game.permanent.token.ThopterColorlessToken;
import java.util.UUID;
@@ -38,7 +39,7 @@ public final class PiaNalaarConsulOfRevival extends CardImpl {
)));
// Whenever you play a land from exile or cast a spell from exile, create a 1/1 colorless Thopter artifact creature token with flying.
- this.addAbility(new PiaNalaarConsulOfRevivalTriggeredAbility());
+ this.addAbility(new PlayLandOrCastSpellFromExileTriggeredAbility(new CreateTokenEffect(new ThopterColorlessToken())));
}
private PiaNalaarConsulOfRevival(final PiaNalaarConsulOfRevival card) {
@@ -50,31 +51,3 @@ public final class PiaNalaarConsulOfRevival extends CardImpl {
return new PiaNalaarConsulOfRevival(this);
}
}
-
-class PiaNalaarConsulOfRevivalTriggeredAbility extends TriggeredAbilityImpl {
-
- PiaNalaarConsulOfRevivalTriggeredAbility() {
- super(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken()));
- setTriggerPhrase("Whenever you play a land from exile or cast a spell from exile, ");
- }
-
- private PiaNalaarConsulOfRevivalTriggeredAbility(final PiaNalaarConsulOfRevivalTriggeredAbility ability) {
- super(ability);
- }
-
- @Override
- public PiaNalaarConsulOfRevivalTriggeredAbility copy() {
- return new PiaNalaarConsulOfRevivalTriggeredAbility(this);
- }
-
- @Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.LAND_PLAYED
- || event.getType() == GameEvent.EventType.SPELL_CAST;
- }
-
- @Override
- public boolean checkTrigger(GameEvent event, Game game) {
- return isControlledBy(event.getPlayerId()) && event.getZone() == Zone.EXILED;
- }
-}
diff --git a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java
index 77fc9965d6a..2f6a81beadb 100644
--- a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java
+++ b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java
@@ -55,7 +55,7 @@ class PlaguecrafterEffect extends OneShotEffect {
PlaguecrafterEffect() {
super(Outcome.Benefit);
- this.staticText = "each player sacrifices a creature or planeswalker. "
+ this.staticText = "each player sacrifices a creature or planeswalker of their choice. "
+ "Each player who can't discards a card.";
}
diff --git a/Mage.Sets/src/mage/cards/p/PolisCrusher.java b/Mage.Sets/src/mage/cards/p/PolisCrusher.java
index 00b0f5d917c..1b615461828 100644
--- a/Mage.Sets/src/mage/cards/p/PolisCrusher.java
+++ b/Mage.Sets/src/mage/cards/p/PolisCrusher.java
@@ -17,7 +17,7 @@ import mage.filter.FilterCard;
import mage.filter.common.FilterEnchantmentCard;
import mage.filter.common.FilterEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -52,7 +52,7 @@ public final class PolisCrusher extends CardImpl {
// Whenever Polis Crusher deals combat damage to a player, if Polis Crusher is monstrous, destroy target enchantment that player controls.
TriggeredAbility ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filterPermanent));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MonstrousCondition.instance,
"Whenever {this} deals combat damage to a player, if {this} is monstrous, destroy target enchantment that player controls."));
diff --git a/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java b/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java
index a91a681c5ab..bb7fc2f8436 100644
--- a/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java
+++ b/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java
@@ -51,7 +51,7 @@ public final class PriestOfForgottenGods extends CardImpl {
);
ability.addEffect(
new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "")
- .setText("and sacrifice a creature")
+ .setText("and sacrifice a creature of their choice")
);
ability.addCost(new SacrificeTargetCost(2, filter));
ability.addEffect(new BasicManaEffect(Mana.BlackMana(2)).setText("You add {B}{B}"));
diff --git a/Mage.Sets/src/mage/cards/p/PriestOfTheCrossing.java b/Mage.Sets/src/mage/cards/p/PriestOfTheCrossing.java
index f35d63dfdad..09ee13e628d 100644
--- a/Mage.Sets/src/mage/cards/p/PriestOfTheCrossing.java
+++ b/Mage.Sets/src/mage/cards/p/PriestOfTheCrossing.java
@@ -9,6 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
+import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
@@ -30,8 +31,13 @@ public class PriestOfTheCrossing extends CardImpl {
// At the beginning of each end step, put X +1/+1 counters on each creature you control, where X is the number of creatures that died under your control this turn.
this.addAbility(new BeginningOfEndStepTriggeredAbility(
- new AddCountersAllEffect(CounterType.P1P1.createInstance(), CreaturesYouControlDiedCount.instance, StaticFilters.FILTER_CONTROLLED_CREATURE)
- .setText("put X +1/+1 counters on each creature you control, where X is the number of creatures that died under your control this turn")));
+ TargetController.ANY,
+ new AddCountersAllEffect(
+ CounterType.P1P1.createInstance(), CreaturesYouControlDiedCount.instance,
+ StaticFilters.FILTER_CONTROLLED_CREATURE
+ ).setText("put X +1/+1 counters on each creature you control, where X is " +
+ "the number of creatures that died under your control this turn"), false
+ ));
}
public PriestOfTheCrossing(PriestOfTheCrossing card) {
diff --git a/Mage.Sets/src/mage/cards/p/PrimordialHydra.java b/Mage.Sets/src/mage/cards/p/PrimordialHydra.java
index 607c850a9e9..b0f7a839133 100644
--- a/Mage.Sets/src/mage/cards/p/PrimordialHydra.java
+++ b/Mage.Sets/src/mage/cards/p/PrimordialHydra.java
@@ -1,7 +1,6 @@
package mage.cards.p;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
@@ -11,6 +10,7 @@ import mage.abilities.effects.common.DoubleCountersSourceEffect;
import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.TrampleAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@@ -24,8 +24,7 @@ import java.util.UUID;
*/
public final class PrimordialHydra extends CardImpl {
- private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1, 10, Integer.MAX_VALUE);
- private static final String staticText = "{this} has trample as long as it has ten or more +1/+1 counters on it";
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1, 10);
public PrimordialHydra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{G}{G}");
@@ -39,13 +38,12 @@ public final class PrimordialHydra extends CardImpl {
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance())));
// At the beginning of your upkeep, double the number of +1/+1 counters on Primordial Hydra.
- this.addAbility(new BeginningOfUpkeepTriggeredAbility(
- new DoubleCountersSourceEffect(CounterType.P1P1)
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoubleCountersSourceEffect(CounterType.P1P1)));
// Primordial Hydra has trample as long as it has ten or more +1/+1 counters on it.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
- new GainAbilitySourceEffect(TrampleAbility.getInstance()), condition, staticText
+ new GainAbilitySourceEffect(TrampleAbility.getInstance()), condition,
+ "{this} has trample as long as it has ten or more +1/+1 counters on it"
)));
}
diff --git a/Mage.Sets/src/mage/cards/p/PsychicWhorl.java b/Mage.Sets/src/mage/cards/p/PsychicWhorl.java
index f35c9339f29..a0dd1da2c3a 100644
--- a/Mage.Sets/src/mage/cards/p/PsychicWhorl.java
+++ b/Mage.Sets/src/mage/cards/p/PsychicWhorl.java
@@ -32,7 +32,7 @@ public final class PsychicWhorl extends CardImpl {
this.getSpellAbility().addTarget(new TargetOpponent());
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new SurveilEffect(2), condition,
- "then if you control a Rat, surveil 2"
+ "Then if you control a Rat, surveil 2"
));
this.getSpellAbility().addHint(hint);
}
diff --git a/Mage.Sets/src/mage/cards/q/Quagnoth.java b/Mage.Sets/src/mage/cards/q/Quagnoth.java
index aeaad7a581c..b9819c458f0 100644
--- a/Mage.Sets/src/mage/cards/q/Quagnoth.java
+++ b/Mage.Sets/src/mage/cards/q/Quagnoth.java
@@ -31,7 +31,7 @@ public final class Quagnoth extends CardImpl {
// When a spell or ability an opponent controls causes you to discard Quagnoth, return it to your hand.
this.addAbility(new DiscardedByOpponentTriggeredAbility(new ReturnToHandSourceEffect()
- .setText("return it to your hand"), true));
+ .setText("return it to your hand")));
}
private Quagnoth(final Quagnoth card) {
diff --git a/Mage.Sets/src/mage/cards/q/QuestForRenewal.java b/Mage.Sets/src/mage/cards/q/QuestForRenewal.java
index c149b9cd6ca..8bf379f74ae 100644
--- a/Mage.Sets/src/mage/cards/q/QuestForRenewal.java
+++ b/Mage.Sets/src/mage/cards/q/QuestForRenewal.java
@@ -1,9 +1,8 @@
-
package mage.cards.q;
-import java.util.UUID;
import mage.abilities.common.BecomesTappedTriggeredAbility;
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.UntapAllDuringEachOtherPlayersUntapStepEffect;
@@ -11,28 +10,33 @@ 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.filter.StaticFilters;
+import java.util.UUID;
+
/**
- *
* @author jeffwadsworth
*/
public final class QuestForRenewal extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4);
+
public QuestForRenewal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
// Whenever a creature you control becomes tapped, you may put a quest counter on Quest for Renewal.
- this.addAbility(new BecomesTappedTriggeredAbility(new AddCountersSourceEffect(CounterType.QUEST.createInstance()),
- true, StaticFilters.FILTER_CONTROLLED_A_CREATURE));
+ this.addAbility(new BecomesTappedTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.QUEST.createInstance()),
+ true, StaticFilters.FILTER_CONTROLLED_A_CREATURE
+ ));
// As long as there are four or more quest counters on Quest for Renewal, untap all creatures you control during each other player's untap step.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES),
- new SourceHasCounterCondition(CounterType.QUEST, 4, Integer.MAX_VALUE),
- "As long as there are four or more quest counters on {this}, untap all creatures you control during each other player's untap step.")));
+ condition, "As long as there are four or more quest counters on {this}, " +
+ "untap all creatures you control during each other player's untap step."
+ )));
}
private QuestForRenewal(final QuestForRenewal card) {
diff --git a/Mage.Sets/src/mage/cards/q/QuestForTheGoblinLord.java b/Mage.Sets/src/mage/cards/q/QuestForTheGoblinLord.java
index 2c8e9d977b8..20f20d6f1b2 100644
--- a/Mage.Sets/src/mage/cards/q/QuestForTheGoblinLord.java
+++ b/Mage.Sets/src/mage/cards/q/QuestForTheGoblinLord.java
@@ -1,39 +1,44 @@
package mage.cards.q;
-import java.util.UUID;
-import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
+import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
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.BoostAllEffect;
+import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.Duration;
+import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
-import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
+import java.util.UUID;
+
/**
- *
* @author jeffwadsworth
*/
public final class QuestForTheGoblinLord extends CardImpl {
- private static final String rule = "As long as {this} has five or more quest counters on it, creatures you control get +2/+0";
- private static final FilterPermanent goblinFilter = new FilterControlledPermanent(SubType.GOBLIN, "a Goblin");
+ private static final FilterPermanent goblinFilter = new FilterControlledPermanent(SubType.GOBLIN, "a Goblin you control");
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 5);
public QuestForTheGoblinLord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}");
// Whenever a Goblin you control enters, you may put a quest counter on Quest for the Goblin Lord.
- this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.QUEST.createInstance()), goblinFilter, true));
+ this.addAbility(new EntersBattlefieldAllTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.QUEST.createInstance()), goblinFilter, true
+ ));
// As long as Quest for the Goblin Lord has five or more quest counters on it, creatures you control get +2/+0.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
- new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES, false),
- new SourceHasCounterCondition(CounterType.QUEST, 5, Integer.MAX_VALUE), rule)));
+ new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield), condition,
+ "as long as {this} has five or more quest counters on it, creatures you control get +2/+0"
+ )));
}
private QuestForTheGoblinLord(final QuestForTheGoblinLord card) {
diff --git a/Mage.Sets/src/mage/cards/q/QuestForUlasTemple.java b/Mage.Sets/src/mage/cards/q/QuestForUlasTemple.java
index 4688f34e747..2ec43db5f13 100644
--- a/Mage.Sets/src/mage/cards/q/QuestForUlasTemple.java
+++ b/Mage.Sets/src/mage/cards/q/QuestForUlasTemple.java
@@ -28,7 +28,7 @@ import java.util.UUID;
public final class QuestForUlasTemple extends CardImpl {
private static final FilterCard filter
- = new FilterCreatureCard("Kraken, Leviathan, Octopus, or Serpent creature card");
+ = new FilterCreatureCard("a Kraken, Leviathan, Octopus, or Serpent creature card");
static {
filter.add(Predicates.or(
diff --git a/Mage.Sets/src/mage/cards/q/QuestingBeast.java b/Mage.Sets/src/mage/cards/q/QuestingBeast.java
index 5e8592460fa..87b9fa0c4a5 100644
--- a/Mage.Sets/src/mage/cards/q/QuestingBeast.java
+++ b/Mage.Sets/src/mage/cards/q/QuestingBeast.java
@@ -21,7 +21,7 @@ import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -57,7 +57,7 @@ public final class QuestingBeast extends CardImpl {
// Whenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls.
Ability ability = new DealsDamageToOpponentTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH), false, true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java
index 1df63b3abe7..ffd15b4f2cf 100644
--- a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java
+++ b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java
@@ -37,7 +37,7 @@ public final class QuillmaneBaku extends CardImpl {
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Quillmane Baku.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {1}, {T}, Remove X ki counters from Quillmane Baku: Return target creature with mana value X or less to its owner's hand.
Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new GenericManaCost(1));
diff --git a/Mage.Sets/src/mage/cards/r/RabidGnaw.java b/Mage.Sets/src/mage/cards/r/RabidGnaw.java
index 5d3c98857f6..253b99df499 100644
--- a/Mage.Sets/src/mage/cards/r/RabidGnaw.java
+++ b/Mage.Sets/src/mage/cards/r/RabidGnaw.java
@@ -22,7 +22,7 @@ public final class RabidGnaw extends CardImpl {
// Target creature you control gets +1/+0 until end of turn. Then it deals damage equal to its power to target creature you don't control.
this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
- this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("then it"));
+ this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("Then it"));
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL));
}
diff --git a/Mage.Sets/src/mage/cards/r/RapidAugmenter.java b/Mage.Sets/src/mage/cards/r/RapidAugmenter.java
index 5eb5962a0ec..c4df7a5e52d 100644
--- a/Mage.Sets/src/mage/cards/r/RapidAugmenter.java
+++ b/Mage.Sets/src/mage/cards/r/RapidAugmenter.java
@@ -3,6 +3,7 @@ package mage.cards.r;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
+import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldCastTriggeredAbility;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
@@ -44,16 +45,16 @@ public final class RapidAugmenter extends CardImpl {
this.addAbility(HasteAbility.getInstance());
// Whenever another creature you control with base power 1 enters, it gains haste until end of turn.
- Ability ability = new EntersBattlefieldControlledTriggeredAbility(
+ Ability ability = new EntersBattlefieldAllTriggeredAbility(
Zone.BATTLEFIELD, new GainAbilityTargetEffect(HasteAbility.getInstance()), filterBP1, false, SetTargetPointer.PERMANENT);
this.addAbility(ability);
// Whenever another creature you control enters, if it wasn't cast, put a +1/+1 counter on Rapid Augmenter
// and Rapid Augmenter can't be blocked this turn.
Ability ability2 = new EntersBattlefieldCastTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(
- CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL,
+ CounterType.P1P1.createInstance()), StaticFilters.FILTER_ANOTHER_CREATURE,
false, SetTargetPointer.PERMANENT, false);
- ability2.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn).concatBy(" and "));
+ ability2.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn).concatBy("and"));
this.addAbility(ability2);
}
@@ -65,4 +66,4 @@ public final class RapidAugmenter extends CardImpl {
public RapidAugmenter copy() {
return new RapidAugmenter(this);
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java
index 46e7d191989..7fffd79eca4 100644
--- a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java
+++ b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java
@@ -1,29 +1,26 @@
package mage.cards.r;
-import java.util.UUID;
-import mage.ApprovingObject;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
-import mage.constants.CardType;
-import mage.constants.Outcome;
-import mage.constants.SubType;
-import mage.constants.SuperType;
-import mage.constants.Zone;
+import mage.constants.*;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
+import mage.util.CardUtil;
import mage.watchers.common.SpellsCastWatcher;
+import java.util.UUID;
+
/**
- *
* @author emerald000
*/
public final class RashmiEternitiesCrafter extends CardImpl {
@@ -56,6 +53,7 @@ class RashmiEternitiesCrafterTriggeredAbility extends SpellCastControllerTrigger
RashmiEternitiesCrafterTriggeredAbility() {
super(new RashmiEternitiesCrafterEffect(), false);
+ setTriggerPhrase("Whenever you cast your first spell each turn, ");
}
private RashmiEternitiesCrafterTriggeredAbility(final RashmiEternitiesCrafterTriggeredAbility ability) {
@@ -69,27 +67,11 @@ class RashmiEternitiesCrafterTriggeredAbility extends SpellCastControllerTrigger
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- if (super.checkTrigger(event, game)) {
- SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
- if (watcher != null && watcher.getCount(event.getPlayerId()) == 1) {
- Spell spell = game.getStack().getSpell(event.getTargetId());
- if (spell != null) {
- for (Effect effect : getEffects()) {
- effect.setValue("RashmiEternitiesCrafterCMC", spell.getManaValue());
- }
- return true;
- }
- }
- }
- return false;
- }
-
- @Override
- public String getRule() {
- return "Whenever you cast your first spell each turn, reveal the top card "
- + "of your library. If it's a nonland card with mana value "
- + "less than that spell's, you may cast it without paying "
- + "its mana cost. If you don't cast the revealed card, put it into your hand.";
+ return super.checkTrigger(event, game)
+ && game
+ .getState()
+ .getWatcher(SpellsCastWatcher.class)
+ .getCount(event.getPlayerId()) == 1;
}
}
@@ -97,10 +79,8 @@ class RashmiEternitiesCrafterEffect extends OneShotEffect {
RashmiEternitiesCrafterEffect() {
super(Outcome.PlayForFree);
- this.staticText = "reveal the top card of your library. If it's a nonland"
- + " card with mana value less than that spell's, you may "
- + "cast it without paying its mana cost. If you don't cast the "
- + "revealed card, put it into your hand";
+ this.staticText = "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.";
}
private RashmiEternitiesCrafterEffect(final RashmiEternitiesCrafterEffect effect) {
@@ -114,32 +94,22 @@ class RashmiEternitiesCrafterEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- boolean cardWasCast = false;
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
- Card card = controller.getLibrary().getFromTop(game);
- if (card != null) {
- controller.revealCards("Rashmi, Eternities Crafter", new CardsImpl(card), game);
- if (card.isLand(game)) {
- controller.moveCards(card, Zone.HAND, source, game);
- return true;
- }
- Object cmcObject = this.getValue("RashmiEternitiesCrafterCMC");
- if (cmcObject != null
- && card.getManaValue() < (int) cmcObject
- && controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName()
- + " without paying its mana cost?", source, game)) {
- game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
- cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
- game, true, new ApprovingObject(source, game));
- game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
- }
- if (!cardWasCast) {
- controller.moveCards(card, Zone.HAND, source, game);
- }
- return true;
- }
+ Player player = game.getPlayer(source.getControllerId());
+ Spell spell = (Spell) getValue("spellCast");
+ if (player == null || spell == null) {
+ return false;
}
- return false;
+ Card card = player.getLibrary().getFromTop(game);
+ if (card == null) {
+ return false;
+ }
+ player.revealCards("Rashmi, Eternities Crafter", new CardsImpl(card), game);
+ FilterCard filter = new FilterCard();
+ filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, spell.getManaValue()));
+ CardUtil.castSpellWithAttributesForFree(player, source, game, card, filter);
+ if (Zone.LIBRARY.match(game.getState().getZone(card.getId()))) {
+ player.moveCards(card, Zone.HAND, source, game);
+ }
+ return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/r/Ratonhnhaketon.java b/Mage.Sets/src/mage/cards/r/Ratonhnhaketon.java
new file mode 100644
index 00000000000..da46c679dc9
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/r/Ratonhnhaketon.java
@@ -0,0 +1,152 @@
+package mage.cards.r;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
+import mage.abilities.condition.common.SourceHasntDealtDamageThisGameCondition;
+import mage.abilities.decorator.ConditionalContinuousEffect;
+import mage.abilities.decorator.ConditionalRestrictionEffect;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect;
+import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
+import mage.abilities.keyword.HexproofAbility;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.filter.FilterCard;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.game.permanent.token.AssassinMenaceToken;
+import mage.game.permanent.token.Token;
+import mage.players.Player;
+import mage.target.common.TargetCardInYourGraveyard;
+import mage.util.CardUtil;
+import mage.watchers.common.DealtDamageThisGameWatcher;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class Ratonhnhaketon extends CardImpl {
+
+ public Ratonhnhaketon(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.ASSASSIN);
+ this.power = new MageInt(3);
+ this.toughness = new MageInt(3);
+
+ // As long as Ratonhnhaketon hasn't dealt damage yet, it has hexproof and can't be blocked.
+ Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect(
+ new GainAbilitySourceEffect(HexproofAbility.getInstance()),
+ SourceHasntDealtDamageThisGameCondition.instance,
+ "as long as {this} hasn't dealt damage yet, it has hexproof"
+ ));
+ ability.addEffect(new ConditionalRestrictionEffect(
+ new CantBeBlockedSourceEffect(),
+ SourceHasntDealtDamageThisGameCondition.instance,
+ "and can't be blocked"
+ ));
+ this.addAbility(ability.addHint(SourceHasntDealtDamageThisGameCondition.getHint()), new DealtDamageThisGameWatcher());
+
+ // Whenever Ratonhnhaketon deals combat damage to a player, create a 1/1 black Assassin creature token with menace. When you do, return target Equipment card from your graveyard to the battlefield, then attach it to that token.
+ this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new RatonhnhaketonTokenEffect()));
+ }
+
+ private Ratonhnhaketon(final Ratonhnhaketon card) {
+ super(card);
+ }
+
+ @Override
+ public Ratonhnhaketon copy() {
+ return new Ratonhnhaketon(this);
+ }
+}
+
+class RatonhnhaketonTokenEffect extends OneShotEffect {
+
+ private static final FilterCard filter = new FilterCard("Equipment card from your graveyard");
+
+ static {
+ filter.add(SubType.EQUIPMENT.getPredicate());
+ }
+
+ RatonhnhaketonTokenEffect() {
+ super(Outcome.Benefit);
+ staticText = "create a 1/1 black Assassin creature token with menace. When you do, return " +
+ "target Equipment card from your graveyard to the battlefield, then attach it to that token";
+ }
+
+ private RatonhnhaketonTokenEffect(final RatonhnhaketonTokenEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public RatonhnhaketonTokenEffect copy() {
+ return new RatonhnhaketonTokenEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Token token = new AssassinMenaceToken();
+ token.putOntoBattlefield(1, game, source);
+ for (UUID tokenId : token.getLastAddedTokenIds()) {
+ Permanent permanent = game.getPermanent(tokenId);
+ if (permanent == null) {
+ continue;
+ }
+ ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
+ new RatonhnhaketonReturnEffect(tokenId), false
+ );
+ ability.addTarget(new TargetCardInYourGraveyard(filter));
+ game.fireReflexiveTriggeredAbility(ability, source);
+ }
+ return true;
+ }
+}
+
+class RatonhnhaketonReturnEffect extends OneShotEffect {
+
+ private final UUID tokenId;
+
+ RatonhnhaketonReturnEffect(UUID tokenId) {
+ super(Outcome.Benefit);
+ staticText = "return target Equipment card from your graveyard to the battlefield, then attach it to that token";
+ this.tokenId = tokenId;
+ }
+
+ private RatonhnhaketonReturnEffect(final RatonhnhaketonReturnEffect effect) {
+ super(effect);
+ this.tokenId = effect.tokenId;
+ }
+
+ @Override
+ public RatonhnhaketonReturnEffect copy() {
+ return new RatonhnhaketonReturnEffect(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) {
+ return false;
+ }
+ player.moveCards(card, Zone.BATTLEFIELD, source, game);
+ Permanent permanent = CardUtil.getPermanentFromCardPutToBattlefield(card, game);
+ if (permanent == null) {
+ return false;
+ }
+ Optional.ofNullable(tokenId)
+ .map(game::getPermanent)
+ .ifPresent(p -> p.addAttachment(permanent.getId(), source, game));
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/r/ReckonerBankbuster.java b/Mage.Sets/src/mage/cards/r/ReckonerBankbuster.java
index 61b07acf81c..c84fa9dc2ec 100644
--- a/Mage.Sets/src/mage/cards/r/ReckonerBankbuster.java
+++ b/Mage.Sets/src/mage/cards/r/ReckonerBankbuster.java
@@ -17,6 +17,7 @@ import mage.abilities.keyword.CrewAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.game.permanent.token.PilotCrewToken;
@@ -29,7 +30,7 @@ import java.util.UUID;
*/
public final class ReckonerBankbuster extends CardImpl {
- private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, 0, 0);
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE, ComparisonType.EQUAL_TO, 0);
public ReckonerBankbuster(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
@@ -50,7 +51,7 @@ public final class ReckonerBankbuster extends CardImpl {
ability.addEffect(new ConditionalOneShotEffect(
new CreateTokenEffect(new TreasureToken()).withAdditionalTokens(new PilotCrewToken()), condition,
"Then if there are no charge counters on {this}, create a Treasure token and a 1/1 colorless " +
- "Pilot creature token with \"This creature crews Vehicles as though its power were 2 greater.\""
+ "Pilot creature token with \"This token crews Vehicles as though its power were 2 greater.\""
));
ability.addCost(new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()));
diff --git a/Mage.Sets/src/mage/cards/r/RegenerationsRestored.java b/Mage.Sets/src/mage/cards/r/RegenerationsRestored.java
index b69745f0c21..74151b0a14a 100644
--- a/Mage.Sets/src/mage/cards/r/RegenerationsRestored.java
+++ b/Mage.Sets/src/mage/cards/r/RegenerationsRestored.java
@@ -3,6 +3,7 @@ package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.OneShotEffect;
@@ -14,6 +15,7 @@ import mage.abilities.keyword.VanishingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.counters.CounterType;
@@ -49,15 +51,15 @@ public final class RegenerationsRestored extends CardImpl {
class RegenerationsRestoredTriggeredAbility extends TriggeredAbilityImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.TIME, ComparisonType.EQUAL_TO, 0);
+
RegenerationsRestoredTriggeredAbility() {
super(Zone.BATTLEFIELD, new ScryEffect(1, false));
this.addEffect(new GainLifeEffect(1).concatBy("and"));
-
this.addEffect(new ConditionalOneShotEffect(
- new RegenerationsRestoredEffect(),
- new SourceHasCounterCondition(CounterType.TIME, 0, 0)
- ).concatBy("Then"));
-
+ new RegenerationsRestoredEffect(), condition, "Then if {this} has no " +
+ "time counters on it, exile it. When you do, take an extra turn after this one"
+ ));
this.setTriggerPhrase("Whenever one or more time counters are removed from {this}, ");
}
@@ -112,4 +114,4 @@ class RegenerationsRestoredEffect extends OneShotEffect {
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/r/ReluctantRoleModel.java b/Mage.Sets/src/mage/cards/r/ReluctantRoleModel.java
new file mode 100644
index 00000000000..91e27171d9d
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/r/ReluctantRoleModel.java
@@ -0,0 +1,95 @@
+package mage.cards.r;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.abilityword.SurvivalAbility;
+import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.counter.AddCounterChoiceSourceEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.constants.SubType;
+import mage.counters.Counter;
+import mage.counters.CounterType;
+import mage.filter.FilterPermanent;
+import mage.filter.common.FilterControlledCreaturePermanent;
+import mage.filter.predicate.permanent.CounterAnyPredicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.target.common.TargetCreaturePermanent;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class ReluctantRoleModel extends CardImpl {
+
+ private static final FilterPermanent filter = new FilterControlledCreaturePermanent();
+
+ static {
+ filter.add(CounterAnyPredicate.instance);
+ }
+
+ public ReluctantRoleModel(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
+
+ this.subtype.add(SubType.HUMAN);
+ this.subtype.add(SubType.SURVIVOR);
+ this.power = new MageInt(2);
+ this.toughness = new MageInt(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.
+ this.addAbility(new SurvivalAbility(new AddCounterChoiceSourceEffect(
+ CounterType.FLYING, CounterType.LIFELINK, CounterType.P1P1
+ ).setText("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.
+ Ability ability = new DiesThisOrAnotherTriggeredAbility(
+ new ReluctantRoleModelEffect(), false, filter
+ ).setApplyFilterOnSource(true);
+ ability.addTarget(new TargetCreaturePermanent(0, 1));
+ this.addAbility(ability);
+ }
+
+ private ReluctantRoleModel(final ReluctantRoleModel card) {
+ super(card);
+ }
+
+ @Override
+ public ReluctantRoleModel copy() {
+ return new ReluctantRoleModel(this);
+ }
+}
+
+class ReluctantRoleModelEffect extends OneShotEffect {
+
+ ReluctantRoleModelEffect() {
+ super(Outcome.Benefit);
+ staticText = "if it had counters on it, put those counters on up to one target creature";
+ }
+
+ private ReluctantRoleModelEffect(final ReluctantRoleModelEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public ReluctantRoleModelEffect copy() {
+ return new ReluctantRoleModelEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Permanent permanent = (Permanent) getValue("creatureDied");
+ Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
+ if (permanent == null || creature == null) {
+ return false;
+ }
+ for (Counter counter : permanent.getCounters(game).values()) {
+ creature.addCounters(counter.copy(), source, game);
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/r/RemoteFarm.java b/Mage.Sets/src/mage/cards/r/RemoteFarm.java
index 83584b66def..035c8f0da5c 100644
--- a/Mage.Sets/src/mage/cards/r/RemoteFarm.java
+++ b/Mage.Sets/src/mage/cards/r/RemoteFarm.java
@@ -1,11 +1,9 @@
-
package mage.cards.r;
-import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.common.EntersBattlefieldTappedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -17,17 +15,21 @@ import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class RemoteFarm extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, ComparisonType.EQUAL_TO, 0);
+
public RemoteFarm(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Remote Farm enters the battlefield tapped with two depletion counters on it.
Ability etbAbility = new EntersBattlefieldAbility(
@@ -35,11 +37,15 @@ public final class RemoteFarm extends CardImpl {
);
etbAbility.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance(2)));
this.addAbility(etbAbility);
+
// {tap}, Remove a depletion counter from Remote Farm: Add {W}{W}. If there are no depletion counters on Remote Farm, sacrifice it.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(2), new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.DEPLETION.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.DEPLETION, 0,0), "If there are no depletion counters on {this}, sacrifice it"));
- this.addAbility(ability);
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no depletion counters on {this}, sacrifice it"
+ ));
+ this.addAbility(ability);
}
private RemoteFarm(final RemoteFarm card) {
diff --git a/Mage.Sets/src/mage/cards/r/ResonanceTechnician.java b/Mage.Sets/src/mage/cards/r/ResonanceTechnician.java
new file mode 100644
index 00000000000..92d8a5e82e8
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/r/ResonanceTechnician.java
@@ -0,0 +1,74 @@
+package mage.cards.r;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.EntersBattlefieldTriggeredAbility;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.common.DiscardCardCost;
+import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.costs.common.TapVariableTargetCost;
+import mage.abilities.dynamicvalue.common.GetXValue;
+import mage.abilities.effects.common.CopyTargetStackObjectEffect;
+import mage.abilities.effects.common.DoIfCostPaid;
+import mage.abilities.effects.keyword.InvestigateEffect;
+import mage.abilities.keyword.FlyingAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.constants.SubType;
+import mage.filter.FilterSpell;
+import mage.filter.common.FilterControlledArtifactPermanent;
+import mage.filter.common.FilterControlledPermanent;
+import mage.filter.common.FilterInstantOrSorcerySpell;
+import mage.filter.predicate.permanent.TappedPredicate;
+import mage.target.TargetSpell;
+import mage.target.targetadjustment.ManaValueTargetAdjuster;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class ResonanceTechnician extends CardImpl {
+
+ private static final FilterControlledPermanent filter = new FilterControlledArtifactPermanent("untapped artifacts you control");
+ private static final FilterSpell filter2 = new FilterInstantOrSorcerySpell("instant or sorcery spell you control with mana value X");
+
+ static {
+ filter.add(TappedPredicate.UNTAPPED);
+ }
+
+ public ResonanceTechnician(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U/R}{U/R}");
+
+ this.subtype.add(SubType.WEIRD);
+ this.subtype.add(SubType.DETECTIVE);
+ this.power = new MageInt(4);
+ this.toughness = new MageInt(4);
+
+ // Flying
+ this.addAbility(FlyingAbility.getInstance());
+
+ // When Resonance Technician enters the battlefield, you may discard a card. If you do, investigate twice.
+ this.addAbility(new EntersBattlefieldTriggeredAbility(
+ new DoIfCostPaid(new InvestigateEffect(2), new DiscardCardCost())
+ ));
+
+ // {T}, Tap X untapped artifacts you control: Copy target instant or sorcery spell you control with mana value X. You may choose new targets for the copy.
+ Ability ability = new SimpleActivatedAbility(new CopyTargetStackObjectEffect(), new TapSourceCost());
+ ability.addCost(new TapVariableTargetCost(filter));
+ ability.addTarget(new TargetSpell(filter2));
+ ability.setTargetAdjuster(new ManaValueTargetAdjuster(GetXValue.instance, ComparisonType.EQUAL_TO));
+ this.addAbility(ability);
+ }
+
+ private ResonanceTechnician(final ResonanceTechnician card) {
+ super(card);
+ }
+
+ @Override
+ public ResonanceTechnician copy() {
+ return new ResonanceTechnician(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/r/RevTitheExtractor.java b/Mage.Sets/src/mage/cards/r/RevTitheExtractor.java
index 0de610319c9..d0e5830262f 100644
--- a/Mage.Sets/src/mage/cards/r/RevTitheExtractor.java
+++ b/Mage.Sets/src/mage/cards/r/RevTitheExtractor.java
@@ -42,7 +42,7 @@ public final class RevTitheExtractor extends CardImpl {
);
ability.addEffect(new ExileFaceDownTopNLibraryYouMayPlayAsLongAsExiledTargetEffect(true, CastManaAdjustment.NONE)
.setText(", then look at the top card of that player's library and exile it face down. "
- + "You may play that card for as long as it remains exiled"));
+ + "You may cast that card for as long as it remains exiled"));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java b/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java
index 66e9db86583..aa21c7f85de 100644
--- a/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java
+++ b/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java
@@ -16,7 +16,7 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -39,7 +39,7 @@ public final class RiptideEntrancer extends CardImpl {
Effect effect = new DoIfCostPaid(new GainControlTargetEffect(Duration.WhileOnBattlefield), new SacrificeSourceCost());
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
// Morph {U}{U}
diff --git a/Mage.Sets/src/mage/cards/r/RiverDelta.java b/Mage.Sets/src/mage/cards/r/RiverDelta.java
index 2c310984a79..10f4012edba 100644
--- a/Mage.Sets/src/mage/cards/r/RiverDelta.java
+++ b/Mage.Sets/src/mage/cards/r/RiverDelta.java
@@ -1,50 +1,50 @@
-
package mage.cards.r;
-import java.util.UUID;
-import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.mana.SimpleManaAbility;
+import mage.abilities.mana.BlackManaAbility;
+import mage.abilities.mana.BlueManaAbility;
+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 java.util.UUID;
+
/**
- *
* @author Luna Skyrise
*/
public final class RiverDelta extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION);
+
public RiverDelta(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// River Delta doesn't untap during your untap step if it has a depletion counter on it.
- Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true),
- new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE));
- effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it");
- Ability ability = new SimpleStaticAbility(effect);
- this.addAbility(ability);
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(
+ new DontUntapInControllersUntapStepSourceEffect(false, true), condition
+ ).setText("{this} doesn't untap during your untap step if it has a depletion counter on it")));
+
// At the beginning of your upkeep, remove a depletion counter from River Delta.
- Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability2);
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance())
+ ));
+
// {tap}: Add {U} or {B}. Put a depletion counter on River Delta.
- Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlueMana(1), new TapSourceCost());
- ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability3);
- Ability ability4 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlackMana(1), new TapSourceCost());
- ability4.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability4);
+ Ability ability = new BlueManaAbility();
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability);
+ Ability ability2 = new BlackManaAbility();
+ ability2.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability2);
}
private RiverDelta(final RiverDelta card) {
diff --git a/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java
index 3876d87703f..0961a791324 100644
--- a/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java
+++ b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java
@@ -16,8 +16,8 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
+import mage.util.CardUtil;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -59,18 +59,10 @@ enum RiveteersAscendancyPredicate implements ObjectSourcePlayerPredicate {
@Override
public boolean apply(ObjectSourcePlayer input, Game game) {
- return input
- .getObject()
- .getManaValue()
- < input
- .getSource()
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("sacrificedPermanent"))
- .filter(Objects::nonNull)
- .map(Permanent.class::cast)
- .mapToInt(MageObject::getManaValue)
- .max()
- .orElse(0);
+ return CardUtil
+ .getEffectValueFromAbility(input.getSource(), "sacrificedPermanent", Permanent.class)
+ .map(MageObject::getManaValue)
+ .filter(x -> input.getObject().getManaValue() < x)
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/r/RocHatchling.java b/Mage.Sets/src/mage/cards/r/RocHatchling.java
index cab0fa6b356..887e701cdb7 100644
--- a/Mage.Sets/src/mage/cards/r/RocHatchling.java
+++ b/Mage.Sets/src/mage/cards/r/RocHatchling.java
@@ -1,12 +1,10 @@
-
package mage.cards.r;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
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.BoostSourceEffect;
@@ -14,37 +12,50 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
import mage.abilities.keyword.FlyingAbility;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.SubType;
+import mage.constants.ComparisonType;
import mage.constants.Duration;
-import mage.constants.Zone;
+import mage.constants.SubType;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author LoneFox
*/
public final class RocHatchling extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.SHELL, ComparisonType.EQUAL_TO, 0);
+
public RocHatchling(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}");
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}");
this.subtype.add(SubType.BIRD);
this.power = new MageInt(0);
this.toughness = new MageInt(1);
// Roc Hatchling enters the battlefield with four shell counters on it.
- this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.SHELL.createInstance(4)), "with four shell counters on it"));
+ this.addAbility(new EntersBattlefieldAbility(
+ new AddCountersSourceEffect(CounterType.SHELL.createInstance(4)),
+ "with four shell counters on it"
+ ));
+
// At the beginning of your upkeep, remove a shell counter from Roc Hatchling.
- this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.SHELL.createInstance())));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.SHELL.createInstance())
+ ));
+
// As long as Roc Hatchling has no shell counters on it, it gets +3/+2 and has flying.
Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect(
- new BoostSourceEffect(3, 2, Duration.WhileOnBattlefield),
- new SourceHasCounterCondition(CounterType.SHELL, 0, 0),
- "As long as {this} has no shell counters on it, it gets +3/+2"));
- ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()),
- new SourceHasCounterCondition(CounterType.SHELL, 0, 0), "and has flying"));
+ new BoostSourceEffect(3, 2, Duration.WhileOnBattlefield),
+ condition, "as long as {this} has no shell counters on it, it gets +3/+2"
+ ));
+ ability.addEffect(new ConditionalContinuousEffect(
+ new GainAbilitySourceEffect(FlyingAbility.getInstance()),
+ condition, "and has flying"
+ ));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java
index e3b85be0f7a..c1aee4820f0 100644
--- a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java
+++ b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java
@@ -1,4 +1,3 @@
-
package mage.cards.r;
import mage.MageInt;
@@ -16,7 +15,8 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.target.common.TargetCardInYourGraveyard;
@@ -29,6 +29,11 @@ import java.util.UUID;
*/
public final class RonaDiscipleOfGix extends CardImpl {
+ private static final FilterCard filter = new FilterCard("historic card from your graveyard");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
+
public RonaDiscipleOfGix(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}");
@@ -45,7 +50,7 @@ public final class RonaDiscipleOfGix extends CardImpl {
.setText("exile target historic card from your graveyard. (Artifacts, legendaries, and Sagas are historic.)"),
true
);
- ability.addTarget(new TargetCardInYourGraveyard(new FilterHistoricCard("historic card from your graveyard")));
+ ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
// You may cast nonland cards exiled with Rona.
diff --git a/Mage.Sets/src/mage/cards/r/RottenmouthViper.java b/Mage.Sets/src/mage/cards/r/RottenmouthViper.java
index 4d55d36b158..a23d3f76b66 100644
--- a/Mage.Sets/src/mage/cards/r/RottenmouthViper.java
+++ b/Mage.Sets/src/mage/cards/r/RottenmouthViper.java
@@ -71,7 +71,7 @@ class RottenmouthViperEffect extends OneShotEffect{
RottenmouthViperEffect(DynamicValue blightCounterAmount) {
super(Outcome.LoseLife);
this.blightCounterAmount = blightCounterAmount;
- this.staticText = "Then for each blight counter on it, each opponent loses 4 life unless that player sacrifices a nonland permanent or discards a card.";
+ this.staticText = "Then for each blight counter on it, each opponent loses 4 life unless that player sacrifices a nonland permanent of their choice or discards a card.";
}
private RottenmouthViperEffect(final RottenmouthViperEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/r/RunawaySteamKin.java b/Mage.Sets/src/mage/cards/r/RunawaySteamKin.java
index e4339e4fabd..97e836411ea 100644
--- a/Mage.Sets/src/mage/cards/r/RunawaySteamKin.java
+++ b/Mage.Sets/src/mage/cards/r/RunawaySteamKin.java
@@ -1,26 +1,27 @@
package mage.cards.r;
-import java.util.UUID;
import mage.MageInt;
import mage.Mana;
import mage.ObjectColor;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.mana.SimpleManaAbility;
-import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ColorPredicate;
+import java.util.UUID;
+
/**
- *
* @author TheElk801
*/
public final class RunawaySteamKin extends CardImpl {
@@ -31,6 +32,8 @@ public final class RunawaySteamKin extends CardImpl {
filter.add(new ColorPredicate(ObjectColor.RED));
}
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1, ComparisonType.FEWER_THAN, 3);
+
public RunawaySteamKin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}");
@@ -39,16 +42,9 @@ public final class RunawaySteamKin extends CardImpl {
this.toughness = new MageInt(1);
// Whenever you cast a red spell, if Runaway Steam-Kin has fewer than three +1/+1 counters on it, put a +1/+1 counter on Runaway Steam-Kin.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new SpellCastControllerTriggeredAbility(
- new AddCountersSourceEffect(
- CounterType.P1P1.createInstance()
- ), filter, false
- ), new SourceHasCounterCondition(CounterType.P1P1, 0, 2),
- "Whenever you cast a red spell, "
- + "if {this} has fewer than three +1/+1 counters on it, "
- + "put a +1/+1 counter on {this}."
- ));
+ this.addAbility(new SpellCastControllerTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter, false
+ ).withInterveningIf(condition));
// Remove three +1/+1 counters from Runaway Steam-Kin: Add {R}{R}{R}.
this.addAbility(new SimpleManaAbility(
diff --git a/Mage.Sets/src/mage/cards/r/RustmouthOgre.java b/Mage.Sets/src/mage/cards/r/RustmouthOgre.java
index e2b48e23a17..4707d7ef988 100644
--- a/Mage.Sets/src/mage/cards/r/RustmouthOgre.java
+++ b/Mage.Sets/src/mage/cards/r/RustmouthOgre.java
@@ -11,7 +11,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -33,7 +33,7 @@ public final class RustmouthOgre extends CardImpl {
// Whenever Rustmouth Ogre deals combat damage to a player, you may destroy target artifact that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SaheeliRadiantCreator.java b/Mage.Sets/src/mage/cards/s/SaheeliRadiantCreator.java
index 970968117af..52f3aa5c77b 100644
--- a/Mage.Sets/src/mage/cards/s/SaheeliRadiantCreator.java
+++ b/Mage.Sets/src/mage/cards/s/SaheeliRadiantCreator.java
@@ -1,6 +1,5 @@
package mage.cards.s;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
@@ -11,12 +10,12 @@ import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.DoWhenCostPaid;
import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
-import mage.constants.Outcome;
-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.SubType;
+import mage.constants.SuperType;
import mage.filter.FilterSpell;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
@@ -24,13 +23,14 @@ import mage.game.Game;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
+import java.util.UUID;
+
/**
- *
* @author Jmlundeen
*/
public final class SaheeliRadiantCreator extends CardImpl {
- private static final FilterSpell filter = new FilterSpell("Artificer or artifact spell");
+ private static final FilterSpell filter = new FilterSpell("an Artificer or artifact spell");
static {
filter.add(Predicates.or(
@@ -41,7 +41,7 @@ public final class SaheeliRadiantCreator extends CardImpl {
public SaheeliRadiantCreator(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}{R}");
-
+
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ARTIFICER);
@@ -105,4 +105,4 @@ class SaheeliRadiantCreatorCopyEffect extends OneShotEffect {
effect.sacrificeTokensCreatedAtNextEndStep(game, source);
return true;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/s/SamutTheDrivingForce.java b/Mage.Sets/src/mage/cards/s/SamutTheDrivingForce.java
index 23211469d08..9c982004f92 100644
--- a/Mage.Sets/src/mage/cards/s/SamutTheDrivingForce.java
+++ b/Mage.Sets/src/mage/cards/s/SamutTheDrivingForce.java
@@ -18,7 +18,7 @@ import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import java.util.UUID;
@@ -27,7 +27,10 @@ import java.util.UUID;
*/
public final class SamutTheDrivingForce extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard("noncreature spells");
+ private static final FilterCard filter = new FilterCard("noncreature spells");
+ static {
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
+ }
public SamutTheDrivingForce(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{W}");
diff --git a/Mage.Sets/src/mage/cards/s/SamwiseGamgee.java b/Mage.Sets/src/mage/cards/s/SamwiseGamgee.java
index e5108ef9fd4..87c4fb3fe9d 100644
--- a/Mage.Sets/src/mage/cards/s/SamwiseGamgee.java
+++ b/Mage.Sets/src/mage/cards/s/SamwiseGamgee.java
@@ -16,12 +16,11 @@ import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledPermanent;
-import mage.filter.common.FilterHistoricCard;
import mage.filter.predicate.mageobject.AnotherPredicate;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.permanent.token.FoodToken;
import mage.target.common.TargetCardInYourGraveyard;
-import mage.target.common.TargetControlledPermanent;
import java.util.UUID;
@@ -32,11 +31,12 @@ public final class SamwiseGamgee extends CardImpl {
private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another nontoken creature");
private static final FilterControlledPermanent filter2 = new FilterControlledPermanent(SubType.FOOD, "Foods");
- private static final FilterCard filter3 = new FilterHistoricCard("historic card from your graveyard");
+ private static final FilterCard filter3 = new FilterCard("historic card from your graveyard");
static {
filter.add(AnotherPredicate.instance);
filter.add(TokenPredicate.FALSE);
+ filter3.add(HistoricPredicate.instance);
}
public SamwiseGamgee(UUID ownerId, CardSetInfo setInfo) {
diff --git a/Mage.Sets/src/mage/cards/s/SanctumSpirit.java b/Mage.Sets/src/mage/cards/s/SanctumSpirit.java
index cfc17b42039..0faca217120 100644
--- a/Mage.Sets/src/mage/cards/s/SanctumSpirit.java
+++ b/Mage.Sets/src/mage/cards/s/SanctumSpirit.java
@@ -1,20 +1,20 @@
-
package mage.cards.s;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.IndestructibleAbility;
-import mage.constants.SubType;
import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
-import mage.constants.Zone;
-import mage.filter.common.FilterHistoricCard;
+import mage.constants.SubType;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
+
+import java.util.UUID;
/**
*
@@ -22,6 +22,11 @@ import mage.filter.common.FilterHistoricCard;
*/
public final class SanctumSpirit extends CardImpl {
+ private static final FilterCard filter = new FilterCard("a historic card");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
+
public SanctumSpirit(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
@@ -36,7 +41,7 @@ public final class SanctumSpirit extends CardImpl {
this.addAbility(
new SimpleActivatedAbility(
new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn),
- new DiscardCardCost(new FilterHistoricCard())
+ new DiscardCardCost(filter)
)
);
}
diff --git a/Mage.Sets/src/mage/cards/s/SandGolem.java b/Mage.Sets/src/mage/cards/s/SandGolem.java
index c54428fb8e6..cba5c7b495b 100644
--- a/Mage.Sets/src/mage/cards/s/SandGolem.java
+++ b/Mage.Sets/src/mage/cards/s/SandGolem.java
@@ -32,7 +32,7 @@ public final class SandGolem extends CardImpl {
new ReturnSourceFromGraveyardToBattlefieldWithCounterEffect(CounterType.P1P1.createInstance(), false)));
effect.setText("return {this} from your graveyard to the battlefield with a +1/+1 counter on it at the beginning of the next end step");
- this.addAbility(new DiscardedByOpponentTriggeredAbility(effect, true));
+ this.addAbility(new DiscardedByOpponentTriggeredAbility(effect));
}
private SandGolem(final SandGolem card) {
diff --git a/Mage.Sets/src/mage/cards/s/SandstoneNeedle.java b/Mage.Sets/src/mage/cards/s/SandstoneNeedle.java
index f4c019a1bd8..4fd89ce73f2 100644
--- a/Mage.Sets/src/mage/cards/s/SandstoneNeedle.java
+++ b/Mage.Sets/src/mage/cards/s/SandstoneNeedle.java
@@ -1,11 +1,9 @@
-
package mage.cards.s;
-import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.common.EntersBattlefieldTappedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -17,17 +15,21 @@ import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class SandstoneNeedle extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, ComparisonType.EQUAL_TO, 0);
+
public SandstoneNeedle(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Sandstone Needle enters the battlefield tapped with two depletion counters on it.
Ability etbAbility = new EntersBattlefieldAbility(
@@ -35,10 +37,14 @@ public final class SandstoneNeedle extends CardImpl {
);
etbAbility.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance(2)));
this.addAbility(etbAbility);
+
// {tap}, Remove a depletion counter from Sandstone Needle: Add {R}{R}. If there are no depletion counters on Sandstone Needle, sacrifice it.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(2), new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.DEPLETION.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.DEPLETION, 0,0), "If there are no depletion counters on {this}, sacrifice it"));
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no depletion counters on {this}, sacrifice it"
+ ));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SaprazzanSkerry.java b/Mage.Sets/src/mage/cards/s/SaprazzanSkerry.java
index ba09afc094f..5b5d55327fa 100644
--- a/Mage.Sets/src/mage/cards/s/SaprazzanSkerry.java
+++ b/Mage.Sets/src/mage/cards/s/SaprazzanSkerry.java
@@ -1,11 +1,10 @@
package mage.cards.s;
-import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
-import mage.abilities.common.EntersBattlefieldTappedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -17,17 +16,21 @@ import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.Zone;
import mage.counters.CounterType;
+import java.util.UUID;
+
/**
- *
* @author Plopman
*/
public final class SaprazzanSkerry extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION, ComparisonType.EQUAL_TO, 0);
+
public SaprazzanSkerry(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Saprazzan Skerry enters the battlefield tapped with two depletion counters on it.
Ability etbAbility = new EntersBattlefieldAbility(
@@ -35,10 +38,14 @@ public final class SaprazzanSkerry extends CardImpl {
);
etbAbility.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance(2)));
this.addAbility(etbAbility);
+
// {tap}, Remove a depletion counter from Saprazzan Skerry: Add {U}{U}. If there are no depletion counters on Saprazzan Skerry, sacrifice it.
Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.BlueMana(2), new TapSourceCost());
ability.addCost(new RemoveCountersSourceCost(CounterType.DEPLETION.createInstance(1)));
- ability.addEffect(new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SourceHasCounterCondition(CounterType.DEPLETION, 0,0), "If there are no depletion counters on {this}, sacrifice it"));
+ ability.addEffect(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), condition,
+ "If there are no depletion counters on {this}, sacrifice it"
+ ));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SarahJaneSmith.java b/Mage.Sets/src/mage/cards/s/SarahJaneSmith.java
index 7e7144c1c9e..799f88f9693 100644
--- a/Mage.Sets/src/mage/cards/s/SarahJaneSmith.java
+++ b/Mage.Sets/src/mage/cards/s/SarahJaneSmith.java
@@ -9,8 +9,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import java.util.UUID;
@@ -19,8 +18,6 @@ import java.util.UUID;
*/
public final class SarahJaneSmith extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
-
public SarahJaneSmith(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
@@ -32,7 +29,7 @@ public final class SarahJaneSmith extends CardImpl {
// Whenever you cast a historic spell, investigate. This ability triggers only once each turn.
this.addAbility(new SpellCastControllerTriggeredAbility(
- new InvestigateEffect(), filter, false
+ new InvestigateEffect(), StaticFilters.FILTER_SPELL_HISTORIC, false
).setTriggersLimitEachTurn(1));
// Doctor's companion
diff --git a/Mage.Sets/src/mage/cards/s/SawInHalf.java b/Mage.Sets/src/mage/cards/s/SawInHalf.java
index 8a27e8a1e14..7d7d9c93458 100644
--- a/Mage.Sets/src/mage/cards/s/SawInHalf.java
+++ b/Mage.Sets/src/mage/cards/s/SawInHalf.java
@@ -43,8 +43,8 @@ class SawInHalfEffect extends OneShotEffect {
SawInHalfEffect() {
super(Outcome.Benefit);
staticText = "destroy target creature. If that creature dies this way, its controller creates " +
- "two tokens that are copies of that creature, except their base power is half that creature's " +
- "power and their base toughness is half that creature's toughness. Round up each time";
+ "two tokens that are copies of that creature, except their power is half that creature's " +
+ "power and their toughness is half that creature's toughness. Round up each time";
}
private SawInHalfEffect(final SawInHalfEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/s/ScaledHulk.java b/Mage.Sets/src/mage/cards/s/ScaledHulk.java
index 1bb3ca44ed0..778add52960 100644
--- a/Mage.Sets/src/mage/cards/s/ScaledHulk.java
+++ b/Mage.Sets/src/mage/cards/s/ScaledHulk.java
@@ -25,7 +25,7 @@ public final class ScaledHulk extends CardImpl {
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Whenever you cast a Spirit or Arcane spell, Scaled Hulk gets +2/+2 until end of turn.
- this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false));
}
private ScaledHulk(final ScaledHulk card) {
diff --git a/Mage.Sets/src/mage/cards/s/SchemaThief.java b/Mage.Sets/src/mage/cards/s/SchemaThief.java
index c439e1bb4d1..6b1c81c4009 100644
--- a/Mage.Sets/src/mage/cards/s/SchemaThief.java
+++ b/Mage.Sets/src/mage/cards/s/SchemaThief.java
@@ -11,7 +11,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -38,7 +38,7 @@ public final class SchemaThief extends CardImpl {
// Whenever Schema Thief deals combat damage to a player, create a token that's a copy of target artifact that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenCopyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SchemingFence.java b/Mage.Sets/src/mage/cards/s/SchemingFence.java
index ae9cff75262..a71d64c5199 100644
--- a/Mage.Sets/src/mage/cards/s/SchemingFence.java
+++ b/Mage.Sets/src/mage/cards/s/SchemingFence.java
@@ -19,7 +19,6 @@ import mage.target.TargetPermanent;
import mage.target.common.TargetNonlandPermanent;
import mage.util.CardUtil;
-import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
@@ -215,12 +214,9 @@ class SchemingFenceManaEffect extends AsThoughEffectImpl implements AsThoughMana
@Override
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
return source.isControlledBy(playerId)
- && affectedAbility
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("schemingFence"))
- .filter(Objects::nonNull)
- .anyMatch(source.getSourceId()::equals);
+ && CardUtil.getEffectValueFromAbility(affectedAbility, "schemingFence", UUID.class)
+ .filter(source.getSourceId()::equals)
+ .isPresent();
}
@Override
diff --git a/Mage.Sets/src/mage/cards/s/ScionOfCalamity.java b/Mage.Sets/src/mage/cards/s/ScionOfCalamity.java
index f22ce9b6086..f4191d15b57 100644
--- a/Mage.Sets/src/mage/cards/s/ScionOfCalamity.java
+++ b/Mage.Sets/src/mage/cards/s/ScionOfCalamity.java
@@ -11,7 +11,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -36,7 +36,7 @@ public final class ScionOfCalamity extends CardImpl {
// Whenever Scion of Calamity deals combat damage to a player, destroy target artifact or enchantment that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/ScionOfDarkness.java b/Mage.Sets/src/mage/cards/s/ScionOfDarkness.java
index 7f6fb900001..4340d3a8624 100644
--- a/Mage.Sets/src/mage/cards/s/ScionOfDarkness.java
+++ b/Mage.Sets/src/mage/cards/s/ScionOfDarkness.java
@@ -14,7 +14,7 @@ import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -39,7 +39,7 @@ public final class ScionOfDarkness extends CardImpl {
// Whenever Scion of Darkness deals combat damage to a player, you may put target creature card from that player's graveyard onto the battlefield under your control.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true, true);
ability.addTarget(new TargetCardInGraveyard(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
// Cycling {3}
diff --git a/Mage.Sets/src/mage/cards/s/ScreamingSwarm.java b/Mage.Sets/src/mage/cards/s/ScreamingSwarm.java
index 4a3fed21002..249cb4fbc23 100644
--- a/Mage.Sets/src/mage/cards/s/ScreamingSwarm.java
+++ b/Mage.Sets/src/mage/cards/s/ScreamingSwarm.java
@@ -86,7 +86,7 @@ class ScreamingSwarmEffect extends OneShotEffect {
ScreamingSwarmEffect() {
super(Outcome.Benefit);
- staticText = "put {this} from your graveyard into your library second from the top";
+ staticText = "put this card from your graveyard into your library second from the top";
}
private ScreamingSwarmEffect(final ScreamingSwarmEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/s/SeasonedWarrenguard.java b/Mage.Sets/src/mage/cards/s/SeasonedWarrenguard.java
index 5b12cac1eb3..d4e447e51b9 100644
--- a/Mage.Sets/src/mage/cards/s/SeasonedWarrenguard.java
+++ b/Mage.Sets/src/mage/cards/s/SeasonedWarrenguard.java
@@ -43,7 +43,7 @@ public final class SeasonedWarrenguard extends CardImpl {
// Whenever Seasoned Warrenguard attacks while you control a token, Seasoned Warrenguard gets +2/+0 until end of turn.
this.addAbility(new AttacksTriggeredAbility(
new BoostSourceEffect(2, 0, Duration.EndOfTurn)
- ).withTriggerCondition(condition).addHint(hint));
+ ).withRuleTextReplacement(false).withTriggerCondition(condition).addHint(hint));
}
private SeasonedWarrenguard(final SeasonedWarrenguard card) {
diff --git a/Mage.Sets/src/mage/cards/s/SerraDisciple.java b/Mage.Sets/src/mage/cards/s/SerraDisciple.java
index 3b301726f7f..65784381b24 100644
--- a/Mage.Sets/src/mage/cards/s/SerraDisciple.java
+++ b/Mage.Sets/src/mage/cards/s/SerraDisciple.java
@@ -10,15 +10,12 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import java.util.UUID;
public final class SerraDisciple extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
-
public SerraDisciple(UUID ownerId, CardSetInfo cardSetInfo) {
super(ownerId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
subtype.add(SubType.BIRD, SubType.CLERIC);
@@ -31,7 +28,7 @@ public final class SerraDisciple extends CardImpl {
// Whenever you cast a historic spell, Serra Disciple gets +1/+1 until end of turn
addAbility(new SpellCastControllerTriggeredAbility(
- new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter, false
+ new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_HISTORIC, false
));
}
diff --git a/Mage.Sets/src/mage/cards/s/SerratedArrows.java b/Mage.Sets/src/mage/cards/s/SerratedArrows.java
index e65cf0ba033..64cb51a52f1 100644
--- a/Mage.Sets/src/mage/cards/s/SerratedArrows.java
+++ b/Mage.Sets/src/mage/cards/s/SerratedArrows.java
@@ -1,34 +1,35 @@
package mage.cards.s;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
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.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.Zone;
+import mage.constants.ComparisonType;
import mage.counters.CounterType;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
- *
* @author LevelX2
*/
public final class SerratedArrows extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.ARROWHEAD, ComparisonType.EQUAL_TO, 0);
+
public SerratedArrows(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// Serrated Arrows enters the battlefield with three arrowhead counters on it.
Effect effect = new AddCountersSourceEffect(CounterType.ARROWHEAD.createInstance(3));
@@ -36,16 +37,12 @@ public final class SerratedArrows extends CardImpl {
this.addAbility(new EntersBattlefieldAbility(effect));
// At the beginning of your upkeep, if there are no arrowhead counters on Serrated Arrows, sacrifice it.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect()),
- new SourceHasCounterCondition(CounterType.ARROWHEAD, 0, 0),
- "At the beginning of your upkeep, if there are no arrowhead counters on {this}, sacrifice it"
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect().setText("sacrifice it")).withInterveningIf(condition));
// {T}, Remove an arrowhead counter from Serrated Arrows: Put a -1/-1 counter on target creature.
Ability ability = new SimpleActivatedAbility(
- new AddCountersTargetEffect(CounterType.M1M1.createInstance()),
- new TapSourceCost());
+ new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new TapSourceCost()
+ );
ability.addCost(new RemoveCountersSourceCost(CounterType.ARROWHEAD.createInstance()));
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/s/ShadowMysteriousAssassin.java b/Mage.Sets/src/mage/cards/s/ShadowMysteriousAssassin.java
index 68dd09b574a..c1e091b2b31 100644
--- a/Mage.Sets/src/mage/cards/s/ShadowMysteriousAssassin.java
+++ b/Mage.Sets/src/mage/cards/s/ShadowMysteriousAssassin.java
@@ -83,6 +83,7 @@ class ShadowMysteriousAssassinEffect extends OneShotEffect {
return false;
}
TargetSacrifice target = new TargetSacrifice(0, 1, filter);
+ player.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent == null || !permanent.sacrifice(source, game)) {
return false;
diff --git a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
index 93f2129b3ae..97e6883c30a 100644
--- a/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
+++ b/Mage.Sets/src/mage/cards/s/SharkTyphoon.java
@@ -118,6 +118,6 @@ class SharkTyphoonTriggeredAbility extends ZoneChangeTriggeredAbility {
@Override
public String getRule() {
- return "When you cycle {this}, create an X/X blue Shark creature token with flying.";
+ return "When you cycle this card, create an X/X blue Shark creature token with flying.";
}
}
diff --git a/Mage.Sets/src/mage/cards/s/SharpEyedRookie.java b/Mage.Sets/src/mage/cards/s/SharpEyedRookie.java
index c164cb2ccb1..ac0ed0df52a 100644
--- a/Mage.Sets/src/mage/cards/s/SharpEyedRookie.java
+++ b/Mage.Sets/src/mage/cards/s/SharpEyedRookie.java
@@ -14,6 +14,7 @@ import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
+import mage.util.CardUtil;
import java.util.UUID;
@@ -68,17 +69,13 @@ class SharpEyedRookieTriggeredAbility extends EntersBattlefieldAllTriggeredAbili
@Override
public boolean checkInterveningIfClause(Game game) {
Permanent sourcePermanent = getSourcePermanentOrLKI(game);
- Permanent permanentEntering = (Permanent) this
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("permanentEnteringBattlefield"))
- .findFirst()
- .orElse(null);
return sourcePermanent != null
- && permanentEntering != null
&& sourcePermanent.isCreature(game)
- && permanentEntering.isCreature(game)
- && (permanentEntering.getPower().getValue() > sourcePermanent.getPower().getValue()
- || permanentEntering.getToughness().getValue() > sourcePermanent.getToughness().getValue());
+ && CardUtil
+ .getEffectValueFromAbility(this, "permanentEnteringBattlefield", Permanent.class)
+ .filter(permanent -> permanent.isCreature(game))
+ .filter(permanent -> sourcePermanent.getPower().getValue() < permanent.getPower().getValue()
+ || sourcePermanent.getToughness().getValue() < permanent.getToughness().getValue())
+ .isPresent();
}
}
diff --git a/Mage.Sets/src/mage/cards/s/ShieldMare.java b/Mage.Sets/src/mage/cards/s/ShieldMare.java
index 1a88cd50c2b..47f62ceef21 100644
--- a/Mage.Sets/src/mage/cards/s/ShieldMare.java
+++ b/Mage.Sets/src/mage/cards/s/ShieldMare.java
@@ -45,7 +45,7 @@ public final class ShieldMare extends CardImpl {
// When Shield Mare enters the battlefield or becomes the target of a spell or ability and opponent controls, you gain 3 life.
this.addAbility(new OrTriggeredAbility(Zone.ALL, new GainLifeEffect(3), false,
- "Whenever {this} enters or becomes the target of a spell or ability an opponent controls, ",
+ "When {this} enters or becomes the target of a spell or ability an opponent controls, ",
new EntersBattlefieldTriggeredAbility(null),
new BecomesTargetSourceTriggeredAbility(null, StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS)));
}
diff --git a/Mage.Sets/src/mage/cards/s/ShorelineLooter.java b/Mage.Sets/src/mage/cards/s/ShorelineLooter.java
index a26d4ab8172..04ee4a103ff 100644
--- a/Mage.Sets/src/mage/cards/s/ShorelineLooter.java
+++ b/Mage.Sets/src/mage/cards/s/ShorelineLooter.java
@@ -40,7 +40,7 @@ public final class ShorelineLooter extends CardImpl {
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1));
ability.addEffect(new ConditionalOneShotEffect(
new DiscardControllerEffect(1), condition,
- "then discard a card unless seven or more cards are in your graveyard"
+ "Then discard a card unless seven or more cards are in your graveyard"
));
this.addAbility(ability.setAbilityWord(AbilityWord.THRESHOLD));
}
diff --git a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java
index e2d93bd8223..7856263da01 100644
--- a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java
+++ b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java
@@ -14,7 +14,7 @@ import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -40,7 +40,7 @@ public final class SigilOfSleep extends CardImpl {
Effect effect = new ReturnToHandTargetEffect();
ability = new DealsDamageToAPlayerAttachedTriggeredAbility(effect, "enchanted", false, true, false);
ability.addTarget(new TargetCreaturePermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SimicAscendancy.java b/Mage.Sets/src/mage/cards/s/SimicAscendancy.java
index 597f89cae71..bc8552fd34a 100644
--- a/Mage.Sets/src/mage/cards/s/SimicAscendancy.java
+++ b/Mage.Sets/src/mage/cards/s/SimicAscendancy.java
@@ -2,18 +2,18 @@ package mage.cards.s;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
+import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
@@ -21,19 +21,23 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledCreaturePermanent;
+import java.util.Optional;
import java.util.UUID;
/**
* @author jmharmon
*/
-
public final class SimicAscendancy extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.GROWTH, 20);
+
public SimicAscendancy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{U}");
// {1}{G}{U}: Put a +1/+1 counter on target creature you control.
- Ability ability = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{1}{G}{U}"));
+ Ability ability = new SimpleActivatedAbility(
+ new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{1}{G}{U}")
+ );
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
@@ -41,14 +45,7 @@ public final class SimicAscendancy extends CardImpl {
this.addAbility(new SimicAscendancyTriggeredAbility());
// At the beginning of your upkeep, if Simic Ascendancy has twenty or more growth counters on it, you win the game.
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfUpkeepTriggeredAbility(
- Zone.BATTLEFIELD, TargetController.YOU, new WinGameSourceControllerEffect(),
- false
- ), new SourceHasCounterCondition(CounterType.GROWTH, 20, Integer.MAX_VALUE),
- "At the beginning of your upkeep, if {this} has twenty " +
- "or more growth counters on it, you win the game"
- ));
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WinGameSourceControllerEffect()).withInterveningIf(condition));
}
private SimicAscendancy(final SimicAscendancy card) {
@@ -64,7 +61,8 @@ public final class SimicAscendancy extends CardImpl {
class SimicAscendancyTriggeredAbility extends TriggeredAbilityImpl {
SimicAscendancyTriggeredAbility() {
- super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.GROWTH.createInstance()), false);
+ super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.GROWTH.createInstance(), SavedDamageValue.MANY), false);
+ this.setTriggerPhrase("Whenever one or more +1/+1 counters are put on a creature you control, ");
}
private SimicAscendancyTriggeredAbility(final SimicAscendancyTriggeredAbility ability) {
@@ -83,27 +81,21 @@ class SimicAscendancyTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- if (event.getData().equals(CounterType.P1P1.getName()) && event.getAmount() > 0) {
- Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
- if (permanent == null) {
- permanent = game.getPermanentEntering(event.getTargetId());
- }
- if (permanent != null
- && !event.getTargetId().equals(this.getSourceId())
- && permanent.isCreature(game)
- && permanent.isControlledBy(this.getControllerId())) {
- this.getEffects().clear();
- if (event.getAmount() > 0) {
- this.addEffect(new AddCountersSourceEffect(CounterType.GROWTH.createInstance(event.getAmount())));
- }
- return true;
- }
+ if (!event.getData().equals(CounterType.P1P1.getName()) || event.getAmount() < 1) {
+ return false;
}
- return false;
- }
-
- @Override
- public String getRule() {
- return "Whenever one or more +1/+1 counters are put on a creature you control, put that many growth counters on {this}.";
+ Permanent permanent = Optional
+ .ofNullable(event)
+ .map(GameEvent::getTargetId)
+ .map(game::getPermanentOrLKIBattlefield)
+ .orElseGet(() -> game.getPermanentEntering(event.getTargetId()));
+ if (permanent == null
+ || event.getTargetId().equals(this.getSourceId())
+ || !permanent.isCreature(game)
+ || !permanent.isControlledBy(this.getControllerId())) {
+ return false;
+ }
+ this.getEffects().setValue("damage", event.getAmount());
+ return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/s/SireOfTheStorm.java b/Mage.Sets/src/mage/cards/s/SireOfTheStorm.java
index 5f0d1e4df7d..ef3142f4e9a 100644
--- a/Mage.Sets/src/mage/cards/s/SireOfTheStorm.java
+++ b/Mage.Sets/src/mage/cards/s/SireOfTheStorm.java
@@ -26,7 +26,7 @@ public final class SireOfTheStorm extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(3);
this.addAbility(FlyingAbility.getInstance());
- this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private SireOfTheStorm(final SireOfTheStorm card) {
diff --git a/Mage.Sets/src/mage/cards/s/Sirocco.java b/Mage.Sets/src/mage/cards/s/Sirocco.java
new file mode 100644
index 00000000000..a85ea85db6e
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/s/Sirocco.java
@@ -0,0 +1,92 @@
+package mage.cards.s;
+
+import mage.ObjectColor;
+import mage.abilities.Ability;
+import mage.abilities.costs.Cost;
+import mage.abilities.costs.common.PayLifeCost;
+import mage.abilities.effects.OneShotEffect;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.ColorPredicate;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.TargetPlayer;
+
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class Sirocco extends CardImpl {
+
+ public Sirocco(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}");
+
+ // Target player reveals their hand. For each blue instant card revealed this way, that player discards that card unless they pay 4 life.
+ this.getSpellAbility().addEffect(new SiroccoEffect());
+ this.getSpellAbility().addTarget(new TargetPlayer());
+ }
+
+ private Sirocco(final Sirocco card) {
+ super(card);
+ }
+
+ @Override
+ public Sirocco copy() {
+ return new Sirocco(this);
+ }
+}
+
+class SiroccoEffect extends OneShotEffect {
+
+ private static final FilterCard filter = new FilterCard("blue instant card");
+
+ static {
+ filter.add(CardType.INSTANT.getPredicate());
+ filter.add(new ColorPredicate(ObjectColor.BLUE));
+ }
+
+ SiroccoEffect() {
+ super(Outcome.Benefit);
+ staticText = "target player reveals their hand. For each blue instant card revealed this way, " +
+ "that player discards that card unless they pay 4 life";
+ }
+
+ private SiroccoEffect(final SiroccoEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public SiroccoEffect copy() {
+ return new SiroccoEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
+ if (player == null || player.getHand().isEmpty()) {
+ return false;
+ }
+ player.revealCards(source, player.getHand(), game);
+ Set cards = player.getHand().getCards(filter, game);
+ if (cards.isEmpty()) {
+ return true;
+ }
+ for (Card card : cards) {
+ Cost cost = new PayLifeCost(4);
+ if (!cost.canPay(source, source, player.getId(), game)
+ || !player.chooseUse(
+ outcome, "Pay 4 life or discard " + card.getIdName() + '?',
+ null, "Pay life", "Discard", source, game
+ ) || !cost.pay(source, game, source, player.getId(), true)) {
+ player.discard(card, false, source, game);
+ }
+ }
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/s/SkirkCommando.java b/Mage.Sets/src/mage/cards/s/SkirkCommando.java
index 1dd7cbb1ddd..14dc245e0ab 100644
--- a/Mage.Sets/src/mage/cards/s/SkirkCommando.java
+++ b/Mage.Sets/src/mage/cards/s/SkirkCommando.java
@@ -13,7 +13,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -35,7 +35,7 @@ public final class SkirkCommando extends CardImpl {
//Whenever Skirk Commando deals combat damage to a player, you may have it deal 2 damage to target creature that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DamageTargetEffect(2), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
//Morph {2}{R} (You may cast this card face down as a 2/2 creature for 3. Turn it face up any time for its morph cost.)
diff --git a/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java b/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java
index 2ae43cc87df..c6f1edcd178 100644
--- a/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java
+++ b/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java
@@ -37,7 +37,7 @@ public final class SkullmaneBaku extends CardImpl {
this.toughness = new MageInt(1);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {1}, {T}, Remove X ki counters from Skullmane Baku: Target creature gets -X/-X until end of turn.
Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn), new GenericManaCost(1));
diff --git a/Mage.Sets/src/mage/cards/s/Skullsnatcher.java b/Mage.Sets/src/mage/cards/s/Skullsnatcher.java
index 8a9a5332f67..8a82f7a47a4 100644
--- a/Mage.Sets/src/mage/cards/s/Skullsnatcher.java
+++ b/Mage.Sets/src/mage/cards/s/Skullsnatcher.java
@@ -16,7 +16,7 @@ import mage.filter.FilterCard;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.UnblockedPredicate;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -47,7 +47,7 @@ public final class Skullsnatcher extends CardImpl {
Effect effect = new ExileTargetEffect(null, "", Zone.GRAVEYARD);
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetCardInGraveyard(0, 2, filterGraveyardCard));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java
index 384c0a73074..b9e313ac4b3 100644
--- a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java
+++ b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java
@@ -44,7 +44,7 @@ public final class SkyfireKirin extends CardImpl {
// Whenever you cast a Spirit or Arcane spell, you may gain control of target creature with that spell's converted mana cost until end of turn.
Ability ability = new SpellCastControllerTriggeredAbility(
new SkyfireKirinEffect(),
- StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD,
+ StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE,
true, SetTargetPointer.SPELL
);
ability.addTarget(new TargetCreaturePermanent());
diff --git a/Mage.Sets/src/mage/cards/s/SnappingThragg.java b/Mage.Sets/src/mage/cards/s/SnappingThragg.java
index e5849354032..476f684aceb 100644
--- a/Mage.Sets/src/mage/cards/s/SnappingThragg.java
+++ b/Mage.Sets/src/mage/cards/s/SnappingThragg.java
@@ -13,7 +13,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -35,7 +35,7 @@ public final class SnappingThragg extends CardImpl {
// Whenever Snapping Thragg deals combat damage to a player, you may have it deal 3 damage to target creature that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DamageTargetEffect(3), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
// Morph {4}{R}{R}
diff --git a/Mage.Sets/src/mage/cards/s/Soilshaper.java b/Mage.Sets/src/mage/cards/s/Soilshaper.java
index 57d2bb86c5b..0ef7ce7f28e 100644
--- a/Mage.Sets/src/mage/cards/s/Soilshaper.java
+++ b/Mage.Sets/src/mage/cards/s/Soilshaper.java
@@ -30,7 +30,7 @@ public final class Soilshaper extends CardImpl {
this.toughness = new MageInt(1);
// Whenever you cast a Spirit or Arcane spell, target land becomes a 3/3 creature until end of turn. It's still a land.
- Ability ability = new SpellCastControllerTriggeredAbility(new BecomesCreatureTargetEffect(new CreatureToken(3, 3), false, true, Duration.EndOfTurn), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new BecomesCreatureTargetEffect(new CreatureToken(3, 3), false, true, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetLandPermanent());
this.addAbility(ability);
}
@@ -44,4 +44,4 @@ public final class Soilshaper extends CardImpl {
return new Soilshaper(this);
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/s/SoulEcho.java b/Mage.Sets/src/mage/cards/s/SoulEcho.java
index 08162fb7a2a..8fd1d2317fb 100644
--- a/Mage.Sets/src/mage/cards/s/SoulEcho.java
+++ b/Mage.Sets/src/mage/cards/s/SoulEcho.java
@@ -1,21 +1,23 @@
-
package mage.cards.s;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
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.ConditionalOneShotEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect;
import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.effects.common.continuous.DontLoseByZeroOrLessLifeEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.constants.Duration;
+import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.DamageEvent;
@@ -27,13 +29,14 @@ import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
- *
* @author L_J
*/
public final class SoulEcho extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.ECHO, ComparisonType.EQUAL_TO, 0);
+
public SoulEcho(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{X}{W}{W}");
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{X}{W}{W}");
// Soul Echo enters the battlefield with X echo counters on it.
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.ECHO.createInstance())));
@@ -43,8 +46,12 @@ public final class SoulEcho extends CardImpl {
// At the beginning of your upkeep, sacrifice Soul Echo if there are no echo counters on it.
// Otherwise, target opponent may choose that for each 1 damage that would be dealt to you until your next upkeep, you remove an echo counter from Soul Echo instead.
- Effect effect = new ConditionalOneShotEffect(new SacrificeSourceEffect(), new SoulEchoOpponentsChoiceEffect(), new SourceHasCounterCondition(CounterType.ECHO, 0, 0), "sacrifice {this} if there are no echo counters on it. Otherwise, target opponent may choose that for each 1 damage that would be dealt to you until your next upkeep, you remove an echo counter from {this} instead");
- Ability ability = new BeginningOfUpkeepTriggeredAbility(effect);
+ Ability ability = new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect(
+ new SacrificeSourceEffect(), new SoulEchoOpponentsChoiceEffect(),
+ condition, "sacrifice {this} if there are no echo counters on it. " +
+ "Otherwise, target opponent may choose that for each 1 damage that would be " +
+ "dealt to you until your next upkeep, you remove an echo counter from {this} instead"
+ ));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
@@ -64,7 +71,7 @@ class SoulEchoOpponentsChoiceEffect extends OneShotEffect {
SoulEchoOpponentsChoiceEffect() {
super(Outcome.PreventDamage);
staticText = "target opponent may choose that for each 1 damage that would be dealt to you " +
- "until your next upkeep, you remove an echo counter from {this} instead";
+ "until your next upkeep, you remove an echo counter from {this} instead";
}
private SoulEchoOpponentsChoiceEffect(final SoulEchoOpponentsChoiceEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/s/SoulOfMagma.java b/Mage.Sets/src/mage/cards/s/SoulOfMagma.java
index fa7299d412a..fa59ca5f2d0 100644
--- a/Mage.Sets/src/mage/cards/s/SoulOfMagma.java
+++ b/Mage.Sets/src/mage/cards/s/SoulOfMagma.java
@@ -25,7 +25,7 @@ public final class SoulOfMagma extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(2);
- Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(1), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(1), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java
index 66aafa4875d..538dcae5506 100644
--- a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java
+++ b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java
@@ -17,6 +17,7 @@ import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.PutCards;
import mage.constants.TargetController;
import mage.counters.CounterType;
@@ -29,7 +30,7 @@ import java.util.UUID;
*/
public final class SoulcipherBoard extends CardImpl {
- private static final Condition condition = new SourceHasCounterCondition(CounterType.OMEN, 0, 0);
+ 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}");
diff --git a/Mage.Sets/src/mage/cards/s/SparkMage.java b/Mage.Sets/src/mage/cards/s/SparkMage.java
index 8eabdbbd9f1..f3b5b2acdbb 100644
--- a/Mage.Sets/src/mage/cards/s/SparkMage.java
+++ b/Mage.Sets/src/mage/cards/s/SparkMage.java
@@ -11,7 +11,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -36,7 +36,7 @@ public final class SparkMage extends CardImpl {
new DamageTargetEffect(1), true, true
).withRuleTextReplacement(false);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/Spellgyre.java b/Mage.Sets/src/mage/cards/s/Spellgyre.java
index 5a99c5e960e..1c0bfc6b358 100644
--- a/Mage.Sets/src/mage/cards/s/Spellgyre.java
+++ b/Mage.Sets/src/mage/cards/s/Spellgyre.java
@@ -25,7 +25,7 @@ public final class Spellgyre extends CardImpl {
this.getSpellAbility().addTarget(new TargetSpell());
// * Surveil 2, then draw two cards.
- this.getSpellAbility().addMode(new Mode(new SurveilEffect(2))
+ this.getSpellAbility().addMode(new Mode(new SurveilEffect(2, false))
.addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then")));
}
diff --git a/Mage.Sets/src/mage/cards/s/StarseerMentor.java b/Mage.Sets/src/mage/cards/s/StarseerMentor.java
index dd0ae2906ae..5e4c4bb4674 100644
--- a/Mage.Sets/src/mage/cards/s/StarseerMentor.java
+++ b/Mage.Sets/src/mage/cards/s/StarseerMentor.java
@@ -54,7 +54,7 @@ public final class StarseerMentor extends CardImpl {
"Sacrifice a nonland permanent or discard a card to prevent losing 3 life?"
)
), YouGainedOrLostLifeCondition.instance, "At the beginning of your end step, if you gained or lost life this turn, "
- + "target opponent loses 3 life unless they sacrifice a nonland permanent or discard a card."
+ + "target opponent loses 3 life unless they sacrifice a nonland permanent of their choice or discard a card."
);
ability.addTarget(new TargetOpponent());
ability.addWatcher(new PlayerGainedLifeWatcher());
diff --git a/Mage.Sets/src/mage/cards/s/SteelSabotage.java b/Mage.Sets/src/mage/cards/s/SteelSabotage.java
index bafd92e25c0..82b0acc36cb 100644
--- a/Mage.Sets/src/mage/cards/s/SteelSabotage.java
+++ b/Mage.Sets/src/mage/cards/s/SteelSabotage.java
@@ -1,28 +1,34 @@
-
package mage.cards.s;
-import java.util.UUID;
import mage.abilities.Mode;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
-import mage.filter.common.FilterArtifactSpell;
+import mage.filter.FilterSpell;
import mage.target.TargetSpell;
import mage.target.common.TargetArtifactPermanent;
+import java.util.UUID;
+
/**
*
* @author North
*/
public final class SteelSabotage extends CardImpl {
+
+ private static final FilterSpell filter = new FilterSpell("artifact spell");
+ static {
+ filter.add(CardType.ARTIFACT.getPredicate());
+ }
+
public SteelSabotage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}");
// Choose one - Counter target artifact spell; or return target artifact to its owner's hand.
this.getSpellAbility().addEffect(new CounterTargetEffect());
- this.getSpellAbility().addTarget(new TargetSpell(new FilterArtifactSpell()));
+ this.getSpellAbility().addTarget(new TargetSpell(filter));
Mode mode = new Mode(new ReturnToHandTargetEffect());
mode.addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addMode(mode);
diff --git a/Mage.Sets/src/mage/cards/s/StragoAndRelm.java b/Mage.Sets/src/mage/cards/s/StragoAndRelm.java
new file mode 100644
index 00000000000..ef49bd3a27c
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/s/StragoAndRelm.java
@@ -0,0 +1,133 @@
+package mage.cards.s;
+
+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.ContinuousEffect;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.SacrificeSourceEffect;
+import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
+import mage.abilities.keyword.HasteAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
+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.Controllable;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.common.TargetOpponent;
+import mage.target.targetpointer.FixedTarget;
+import mage.util.CardUtil;
+
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class StragoAndRelm extends CardImpl {
+
+ public StragoAndRelm(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.WIZARD);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(3);
+
+ // Sketch and Lore -- {2}{R}, {T}: Target opponent exiles cards from the top of their library until they exile an instant, sorcery, or creature card. You may cast that card without paying its mana cost. If you cast a creature spell this way, it gains haste and "At the beginning of the end step, sacrifice this creature." Activate only as a sorcery.
+ Ability ability = new ActivateAsSorceryActivatedAbility(new StragoAndRelmEffect(), new ManaCostsImpl<>("{2}{R}"));
+ ability.addCost(new TapSourceCost());
+ ability.addTarget(new TargetOpponent());
+ this.addAbility(ability.withFlavorWord("Sketch and Lore"));
+ }
+
+ private StragoAndRelm(final StragoAndRelm card) {
+ super(card);
+ }
+
+ @Override
+ public StragoAndRelm copy() {
+ return new StragoAndRelm(this);
+ }
+}
+
+class StragoAndRelmEffect extends OneShotEffect {
+
+ private enum StragoAndRelmTracker implements CardUtil.SpellCastTracker {
+ instance;
+
+ @Override
+ public boolean checkCard(Card card, Game game) {
+ return true;
+ }
+
+ @Override
+ public void addCard(Card card, Ability source, Game game) {
+ if (!card.isCreature(game)) {
+ return;
+ }
+ for (ContinuousEffect effect : Arrays.asList(
+ new GainAbilityTargetEffect(HasteAbility.getInstance()),
+ new GainAbilityTargetEffect(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect()))
+ )) {
+ effect.setTargetPointer(new FixedTarget(card.getId()));
+ game.getState().addEffect(effect, card.getSpellAbility());
+ game.addEffect(effect, source);
+ }
+ }
+ }
+
+ StragoAndRelmEffect() {
+ super(Outcome.Benefit);
+ staticText = "target opponent exiles cards from the top of their library until they exile an " +
+ "instant, sorcery, or creature card. You may cast that card without paying its mana cost. " +
+ "If you cast a creature spell this way, it gains haste and \"At the beginning of the end step, sacrifice this creature.\"";
+ }
+
+ private StragoAndRelmEffect(final StragoAndRelmEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public StragoAndRelmEffect copy() {
+ return new StragoAndRelmEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
+ if (opponent == null) {
+ return false;
+ }
+ Card card = getCard(opponent, game, source);
+ if (card == null) {
+ return false;
+ }
+ Optional.ofNullable(source)
+ .map(Controllable::getControllerId)
+ .map(game::getPlayer)
+ .ifPresent(player -> CardUtil.castSpellWithAttributesForFree(
+ opponent, source, game, new CardsImpl(card),
+ StaticFilters.FILTER_CARD, StragoAndRelmTracker.instance
+ ));
+ 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);
+ if (card.isInstantOrSorcery(game) || card.isCreature(game)) {
+ return card;
+ }
+ }
+ return null;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/s/SummonLeviathan.java b/Mage.Sets/src/mage/cards/s/SummonLeviathan.java
index e3398a1f4a2..e690bd28a75 100644
--- a/Mage.Sets/src/mage/cards/s/SummonLeviathan.java
+++ b/Mage.Sets/src/mage/cards/s/SummonLeviathan.java
@@ -14,7 +14,7 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SagaChapter;
import mage.constants.SubType;
-import mage.filter.FilterPermanent;
+import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.GameEvent;
@@ -27,10 +27,11 @@ import java.util.UUID;
*/
public final class SummonLeviathan extends CardImpl {
- private static final FilterPermanent filter = new FilterPermanent();
+ private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
static {
filter.add(Predicates.not(SubType.KRAKEN.getPredicate()));
+ filter.add(Predicates.not(SubType.LEVIATHAN.getPredicate()));
filter.add(Predicates.not(SubType.MERFOLK.getPredicate()));
filter.add(Predicates.not(SubType.OCTOPUS.getPredicate()));
filter.add(Predicates.not(SubType.SERPENT.getPredicate()));
@@ -102,6 +103,7 @@ class SummonLeviathanTriggeredAbility extends DelayedTriggeredAbility {
&& (permanent.hasSubtype(SubType.KRAKEN, game)
|| permanent.hasSubtype(SubType.LEVIATHAN, game)
|| permanent.hasSubtype(SubType.MERFOLK, game)
- || permanent.hasSubtype(SubType.OCTOPUS, game));
+ || permanent.hasSubtype(SubType.OCTOPUS, game)
+ || permanent.hasSubtype(SubType.SERPENT, game));
}
}
diff --git a/Mage.Sets/src/mage/cards/s/SunderShaman.java b/Mage.Sets/src/mage/cards/s/SunderShaman.java
index 6921a07b61d..8c97e3746c0 100644
--- a/Mage.Sets/src/mage/cards/s/SunderShaman.java
+++ b/Mage.Sets/src/mage/cards/s/SunderShaman.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -38,7 +38,7 @@ public final class SunderShaman extends CardImpl {
// Whenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/s/SurtrFieryJotun.java b/Mage.Sets/src/mage/cards/s/SurtrFieryJotun.java
index c775f00f854..1f8f6eec934 100644
--- a/Mage.Sets/src/mage/cards/s/SurtrFieryJotun.java
+++ b/Mage.Sets/src/mage/cards/s/SurtrFieryJotun.java
@@ -10,8 +10,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.FilterSpell;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
@@ -21,8 +20,6 @@ import java.util.UUID;
*/
public final class SurtrFieryJotun extends CardImpl {
- private static final FilterSpell filter = new FilterHistoricSpell();
-
public SurtrFieryJotun(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}");
@@ -37,7 +34,7 @@ public final class SurtrFieryJotun extends CardImpl {
this.addAbility(TrampleAbility.getInstance());
// Whenever you cast a historic spell, Surtr, Fiery Jotun deals 3 damage to any target.
- Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(3), filter, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(3), StaticFilters.FILTER_SPELL_HISTORIC, false);
ability.addTarget(new TargetAnyTarget());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/Tallowisp.java b/Mage.Sets/src/mage/cards/t/Tallowisp.java
index f56734c047d..bf8df5cd6e2 100644
--- a/Mage.Sets/src/mage/cards/t/Tallowisp.java
+++ b/Mage.Sets/src/mage/cards/t/Tallowisp.java
@@ -1,10 +1,7 @@
-
package mage.cards.t;
-import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
-import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
@@ -19,6 +16,8 @@ import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.target.common.TargetCardInLibrary;
+import java.util.UUID;
+
/**
*
* @author LevelX2
@@ -30,7 +29,7 @@ public final class Tallowisp extends CardImpl {
static {
filterAura.add(CardType.ENCHANTMENT.getPredicate());
filterAura.add(SubType.AURA.getPredicate());
- filterAura.add(new TallowispAbilityPredicate());
+ filterAura.add(TallowispAbilityPredicate.instance);
}
public Tallowisp(UUID ownerId, CardSetInfo setInfo) {
@@ -41,7 +40,7 @@ public final class Tallowisp extends CardImpl {
this.toughness = new MageInt(3);
// Whenever you cast a Spirit or Arcane spell, you may search your library for an Aura card with enchant creature, reveal it, and put it into your hand. If you do, shuffle your library.
- this.addAbility(new SpellCastControllerTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterAura), true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterAura), true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private Tallowisp(final Tallowisp card) {
@@ -54,20 +53,14 @@ public final class Tallowisp extends CardImpl {
}
}
-class TallowispAbilityPredicate implements Predicate {
-
- public TallowispAbilityPredicate() {
- }
+enum TallowispAbilityPredicate implements Predicate {
+ instance;
@Override
public boolean apply(MageObject input, Game game) {
- Abilities abilities = input.getAbilities();
- for (int i = 0; i < abilities.size(); i++) {
- if (abilities.get(i) instanceof EnchantAbility) {
- String enchantText = abilities.get(i).getRule();
- if (enchantText.contentEquals("Enchant creature")) {
- return true;
- }
+ for (Ability ability : input.getAbilities()) {
+ if (ability instanceof EnchantAbility && ability.getRule().contentEquals("Enchant creature")) {
+ return true;
}
}
return false;
diff --git a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java
index d938346820c..3fd3f65fb23 100644
--- a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java
+++ b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java
@@ -13,9 +13,7 @@ import mage.abilities.effects.common.TapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
-import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
-import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.command.emblems.TamiyoFieldResearcherEmblem;
import mage.game.events.DamagedBatchBySourceEvent;
@@ -35,12 +33,6 @@ import java.util.UUID;
*/
public final class TamiyoFieldResearcher extends CardImpl {
- private static final FilterPermanent filter = new FilterPermanent("nonland permanent");
-
- static {
- filter.add(Predicates.not(CardType.LAND.getPredicate()));
- }
-
public TamiyoFieldResearcher(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{G}{W}{U}");
this.supertype.add(SuperType.LEGENDARY);
@@ -55,7 +47,7 @@ public final class TamiyoFieldResearcher extends CardImpl {
// -2: Tap up to two target nonland permanents. They don't untap during their controller's next untap step.
ability = new LoyaltyAbility(new TapTargetEffect(), -2);
- ability.addTarget(new TargetPermanent(0, 2, filter, false));
+ ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_PERMANENTS_NON_LAND, false));
ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("They"));
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/t/TellerOfTales.java b/Mage.Sets/src/mage/cards/t/TellerOfTales.java
index 3a7f5768061..f4c3b6670ba 100644
--- a/Mage.Sets/src/mage/cards/t/TellerOfTales.java
+++ b/Mage.Sets/src/mage/cards/t/TellerOfTales.java
@@ -30,7 +30,7 @@ public final class TellerOfTales extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast a Spirit or Arcane spell, you may tap or untap target creature.
- Ability ability = new SpellCastControllerTriggeredAbility(new MayTapOrUntapTargetEffect(), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true);
+ Ability ability = new SpellCastControllerTriggeredAbility(new MayTapOrUntapTargetEffect(), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java b/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java
index e01c99d833d..b5639028634 100644
--- a/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java
+++ b/Mage.Sets/src/mage/cards/t/TempleOfCyclicalTime.java
@@ -2,6 +2,7 @@ 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;
@@ -11,6 +12,7 @@ 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.constants.Zone;
import mage.counters.CounterType;
@@ -22,6 +24,8 @@ import java.util.UUID;
*/
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;
@@ -35,11 +39,8 @@ public final class TempleOfCyclicalTime extends CardImpl {
// {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(
- Zone.BATTLEFIELD,
- new TransformSourceEffect(),
- new ManaCostsImpl<>("{2}{U}"),
- new SourceHasCounterCondition(CounterType.TIME, 0, 0),
- TimingRule.SORCERY
+ Zone.BATTLEFIELD, new TransformSourceEffect(),
+ new ManaCostsImpl<>("{2}{U}"), condition, TimingRule.SORCERY
);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/t/TemptWithBunnies.java b/Mage.Sets/src/mage/cards/t/TemptWithBunnies.java
index 99c1d414e3e..f25af1112eb 100644
--- a/Mage.Sets/src/mage/cards/t/TemptWithBunnies.java
+++ b/Mage.Sets/src/mage/cards/t/TemptWithBunnies.java
@@ -1,7 +1,5 @@
package mage.cards.t;
-import java.util.UUID;
-
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
@@ -13,8 +11,9 @@ import mage.game.permanent.token.RabbitToken;
import mage.game.permanent.token.Token;
import mage.players.Player;
+import java.util.UUID;
+
/**
- *
* @author Grath
*/
public final class TemptWithBunnies extends CardImpl {
@@ -26,6 +25,7 @@ public final class TemptWithBunnies extends CardImpl {
// card and create a 1/1 white Rabbit creature token. For each opponent who does, you draw a card and you
// create a 1/1 white Rabbit creature token.
this.getSpellAbility().addEffect(new TemptWithBunniesEffect());
+ this.getSpellAbility().withFlavorWord("Tempting Offer");
}
private TemptWithBunnies(final TemptWithBunnies card) {
@@ -42,7 +42,7 @@ class TemptWithBunniesEffect extends OneShotEffect {
TemptWithBunniesEffect() {
super(Outcome.PutLandInPlay);
- this.staticText = "Tempting offer — Draw a card and create a 1/1 white Rabbit creature token. Then each opponent may draw a card and create a 1/1 white Rabbit creature token. For each opponent who does, you draw a card and you create a 1/1 white Rabbit creature token.";
+ this.staticText = "draw a card and create a 1/1 white Rabbit creature token. Then each opponent may draw a card and create a 1/1 white Rabbit creature token. For each opponent who does, you draw a card and you create a 1/1 white Rabbit creature token.";
}
private TemptWithBunniesEffect(final TemptWithBunniesEffect effect) {
@@ -83,4 +83,4 @@ class TemptWithBunniesEffect extends OneShotEffect {
return false;
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Sets/src/mage/cards/t/TenuousTruce.java b/Mage.Sets/src/mage/cards/t/TenuousTruce.java
index cff82aa3cef..88eccd4c5e8 100644
--- a/Mage.Sets/src/mage/cards/t/TenuousTruce.java
+++ b/Mage.Sets/src/mage/cards/t/TenuousTruce.java
@@ -2,10 +2,13 @@ package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.effects.Effect;
-import mage.abilities.effects.common.*;
+import mage.abilities.effects.common.AttachEffect;
+import mage.abilities.effects.common.DrawCardSourceControllerEffect;
+import mage.abilities.effects.common.DrawCardTargetEffect;
+import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.abilities.keyword.EnchantAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@@ -36,8 +39,8 @@ public class TenuousTruce extends CardImpl {
// At the beginning of enchanted opponent’s end step, you and that player each draw a card.
Ability drawAbility = new BeginningOfEndStepTriggeredAbility(
- TargetController.ENCHANTED, new DrawCardSourceControllerEffect(1).setText("you "),
- false);
+ TargetController.ENCHANTED, new DrawCardSourceControllerEffect(1).setText("you"), false
+ ).setTriggerPhrase("At the beginning of enchanted opponent's end step, ");
Effect enchantedPlayerDrawEffect = new DrawCardTargetEffect(1);
enchantedPlayerDrawEffect.concatBy("and").setText("that player each draw a card");
drawAbility.addEffect(enchantedPlayerDrawEffect);
diff --git a/Mage.Sets/src/mage/cards/t/TesharAncestorsApostle.java b/Mage.Sets/src/mage/cards/t/TesharAncestorsApostle.java
index 10463db3189..5cf8715a3ce 100644
--- a/Mage.Sets/src/mage/cards/t/TesharAncestorsApostle.java
+++ b/Mage.Sets/src/mage/cards/t/TesharAncestorsApostle.java
@@ -1,7 +1,6 @@
package mage.cards.t;
-import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
@@ -14,11 +13,13 @@ import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
+import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
-import mage.filter.common.FilterHistoricSpell;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.common.TargetCardInYourGraveyard;
+import java.util.UUID;
+
/**
*
* @author L_J
@@ -46,14 +47,14 @@ public final class TesharAncestorsApostle extends CardImpl {
// Whenever you cast a historic spell, return target creature card with converted mana cost 3 or less from your graveyard to the battlefield.
Ability ability = new SpellCastControllerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()
.setText("return target creature card with mana value 3 or less from your graveyard to the battlefield. "
- + "(Artifacts, legendaries, and Sagas are historic.)"), new FilterHistoricSpell(), false);
+ + "(Artifacts, legendaries, and Sagas are historic.)"), StaticFilters.FILTER_SPELL_HISTORIC, false);
ability.addTarget(new TargetCardInYourGraveyard(filter));
this.addAbility(ability);
}
- private TesharAncestorsApostle(final TesharAncestorsApostle TesharAncestorsApostle) {
- super(TesharAncestorsApostle);
+ private TesharAncestorsApostle(final TesharAncestorsApostle card) {
+ super(card);
}
public TesharAncestorsApostle copy() {
diff --git a/Mage.Sets/src/mage/cards/t/TheCurseOfFenric.java b/Mage.Sets/src/mage/cards/t/TheCurseOfFenric.java
new file mode 100644
index 00000000000..e17de685187
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/t/TheCurseOfFenric.java
@@ -0,0 +1,162 @@
+package mage.cards.t;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.SagaAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.FightTargetsEffect;
+import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect;
+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.NamePredicate;
+import mage.filter.predicate.other.AnotherTargetPredicate;
+import mage.filter.predicate.permanent.TokenPredicate;
+import mage.game.Game;
+import mage.game.permanent.Permanent;
+import mage.game.permanent.token.Mutant33DeathtouchToken;
+import mage.game.permanent.token.Token;
+import mage.game.permanent.token.TokenImpl;
+import mage.target.Target;
+import mage.target.TargetPermanent;
+import mage.target.common.TargetCreaturePermanent;
+import mage.target.targetadjustment.ForEachPlayerTargetsAdjuster;
+import mage.target.targetpointer.EachTargetPointer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * @author padfoothelix
+ */
+public final class TheCurseOfFenric extends CardImpl {
+
+ private static final FilterCreaturePermanent nontokenFilter = new FilterCreaturePermanent("nontoken creature");
+ private static final FilterPermanent mutantFilter = new FilterPermanent(SubType.MUTANT, "mutant");
+ private static final FilterCreaturePermanent fenricFilter = new FilterCreaturePermanent("another target creature named Fenric");
+
+ static {
+ nontokenFilter.add(TokenPredicate.FALSE);
+ fenricFilter.add(new NamePredicate("Fenric"));
+ fenricFilter.add(new AnotherTargetPredicate(2));
+ }
+
+ public TheCurseOfFenric(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{W}");
+
+ 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 -- For each player, destroy up to one target creature that player controls. For each creature destroyed this way, its controller creates a 3/3 green Mutant creature token with deathtouch.
+ sagaAbility.addChapterEffect(
+ this, SagaChapter.CHAPTER_I,
+ ability -> {
+ ability.addEffect(new TheCurseOfFenricDestroyEffect()
+ .setText("for each player, destroy up to one target creature " +
+ "that player controls. For each creature destroyed " +
+ "this way, its controller creates a 3/3 green Mutant " +
+ "creature with deathtouch")
+ .setTargetPointer(new EachTargetPointer())
+ );
+ ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE));
+ ability.setTargetAdjuster(new ForEachPlayerTargetsAdjuster(false, false));
+ }
+ );
+
+
+ // II -- Target nontoken creature becomes a 6/6 legendary Horror creature named Fenric and loses all abilities.
+ sagaAbility.addChapterEffect(
+ this, SagaChapter.CHAPTER_II,
+ new BecomesCreatureTargetEffect(
+ new TheCurseOfFenricHorrorToken(),
+ true, false, Duration.EndOfGame, true
+ ),
+ new TargetCreaturePermanent(nontokenFilter)
+ );
+
+ // III -- Target Mutant fights another target creature named Fenric.
+ sagaAbility.addChapterEffect(
+ this, SagaChapter.CHAPTER_III,
+ ability -> {
+ ability.addEffect(new FightTargetsEffect().setText(
+ "Target Mutant fights another target creature named Fenric"
+ ));
+ ability.addTarget(new TargetPermanent(mutantFilter).setTargetTag(1));
+ ability.addTarget(new TargetCreaturePermanent(fenricFilter).setTargetTag(2));
+ }
+ );
+
+ this.addAbility(sagaAbility);
+ }
+
+ private TheCurseOfFenric(final TheCurseOfFenric card) {
+ super(card);
+ }
+
+ @Override
+ public TheCurseOfFenric copy() {
+ return new TheCurseOfFenric(this);
+ }
+}
+
+class TheCurseOfFenricDestroyEffect extends OneShotEffect {
+
+ TheCurseOfFenricDestroyEffect() {
+ super(Outcome.DestroyPermanent);
+ }
+
+ private TheCurseOfFenricDestroyEffect(final TheCurseOfFenricDestroyEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public TheCurseOfFenricDestroyEffect copy() {
+ return new TheCurseOfFenricDestroyEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Token mutantToken = new Mutant33DeathtouchToken();
+ List playersToCreateToken = new ArrayList<>();
+ for (Target target : source.getTargets()) {
+ Permanent targetCreature = game.getPermanent(target.getFirstTarget());
+ if (targetCreature != null) {
+ UUID controllerId = targetCreature.getControllerId();
+ if (targetCreature.destroy(source, game, false)) {
+ playersToCreateToken.add(controllerId);
+ }
+ }
+ }
+ game.processAction();
+ for (UUID controllerId : playersToCreateToken) {
+ mutantToken.putOntoBattlefield(1, game, source, controllerId);
+ }
+ return true;
+ }
+}
+
+class TheCurseOfFenricHorrorToken extends TokenImpl {
+
+ TheCurseOfFenricHorrorToken() {
+ super("Fenric", "6/6 legendary Horror creature named Fenric");
+ this.supertype.add(SuperType.LEGENDARY);
+ this.cardType.add(CardType.CREATURE);
+ this.subtype.add(SubType.HORROR);
+ this.power = new MageInt(6);
+ this.toughness = new MageInt(6);
+ }
+
+ private TheCurseOfFenricHorrorToken(final TheCurseOfFenricHorrorToken token) {
+ super(token);
+ }
+
+ public TheCurseOfFenricHorrorToken copy() {
+ return new TheCurseOfFenricHorrorToken(this);
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/t/ThiefOfHope.java b/Mage.Sets/src/mage/cards/t/ThiefOfHope.java
index 9f1eda77e5a..32baeef0f98 100644
--- a/Mage.Sets/src/mage/cards/t/ThiefOfHope.java
+++ b/Mage.Sets/src/mage/cards/t/ThiefOfHope.java
@@ -27,7 +27,7 @@ public final class ThiefOfHope extends CardImpl {
this.power = new MageInt(2);
this.toughness = new MageInt(2);
- Ability ability = new SpellCastControllerTriggeredAbility(new LoseLifeTargetEffect(1), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, false);
+ Ability ability = new SpellCastControllerTriggeredAbility(new LoseLifeTargetEffect(1), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, false);
ability.addEffect(new GainLifeEffect(1).concatBy("and"));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/t/ThingInTheIce.java b/Mage.Sets/src/mage/cards/t/ThingInTheIce.java
index fea3d82c6b2..149beca63ac 100644
--- a/Mage.Sets/src/mage/cards/t/ThingInTheIce.java
+++ b/Mage.Sets/src/mage/cards/t/ThingInTheIce.java
@@ -1,15 +1,12 @@
-
package mage.cards.t;
-import java.util.UUID;
-
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
@@ -18,11 +15,14 @@ import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
+import mage.constants.ComparisonType;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
+import java.util.UUID;
+
/**
* @author fireshoes
*/
@@ -36,6 +36,8 @@ public final class ThingInTheIce extends CardImpl {
CardType.SORCERY.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);
@@ -48,20 +50,20 @@ public final class ThingInTheIce extends CardImpl {
this.addAbility(DefenderAbility.getInstance());
// Thing in the Ice enters the battlefield with four ice counters on it.
- Effect effect = new AddCountersSourceEffect(CounterType.ICE.createInstance(4));
- effect.setText("with four ice counters on it");
- this.addAbility(new EntersBattlefieldAbility(effect));
+ this.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());
- effect = new RemoveCounterSourceEffect(CounterType.ICE.createInstance(1));
- effect.setText("remove an ice counter from {this}");
- Ability ability = new SpellCastControllerTriggeredAbility(effect, filter, false);
- effect = new ConditionalOneShotEffect(new TransformSourceEffect(), new SourceHasCounterCondition(CounterType.ICE, 0, 0),
- "Then if it has no ice counters on it, transform it");
- ability.addEffect(effect);
+ Ability ability = new SpellCastControllerTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.ICE.createInstance(1)), filter, false
+ );
+ ability.addEffect(new ConditionalOneShotEffect(
+ new TransformSourceEffect(), condition,
+ "Then if it has no ice counters on it, transform it"
+ ));
this.addAbility(ability);
-
}
private ThingInTheIce(final ThingInTheIce card) {
diff --git a/Mage.Sets/src/mage/cards/t/ThornplateIntimidator.java b/Mage.Sets/src/mage/cards/t/ThornplateIntimidator.java
index fd2921883d5..43f1b367d22 100644
--- a/Mage.Sets/src/mage/cards/t/ThornplateIntimidator.java
+++ b/Mage.Sets/src/mage/cards/t/ThornplateIntimidator.java
@@ -42,7 +42,7 @@ public final class ThornplateIntimidator extends CardImpl {
new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_NON_LAND), new DiscardCardCost()
),
"Sacrifice a nonland permanent or discard a card to prevent losing 3 life?"
- ));
+ ).setText("target opponent loses 3 life unless they sacrifice a nonland permanent of their choice or discard a card"));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/ThroatSlitter.java b/Mage.Sets/src/mage/cards/t/ThroatSlitter.java
index f887b058182..15c49b945eb 100644
--- a/Mage.Sets/src/mage/cards/t/ThroatSlitter.java
+++ b/Mage.Sets/src/mage/cards/t/ThroatSlitter.java
@@ -15,7 +15,7 @@ import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -45,7 +45,7 @@ public final class ThroatSlitter extends CardImpl {
// Whenever Throat Slitter deals combat damage to a player, destroy target nonblack creature that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java b/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java
index 9b141d2c3ae..c24a2f21d88 100644
--- a/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java
+++ b/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java
@@ -1,6 +1,5 @@
package mage.cards.t;
-import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PutCardIntoPlayWithHasteAndSacrificeEffect;
import mage.abilities.keyword.SpliceAbility;
import mage.cards.CardImpl;
@@ -27,7 +26,7 @@ public final class ThroughTheBreach extends CardImpl {
));
// Splice onto Arcane {2}{R}{R}
- this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, new ManaCostsImpl<>("{2}{R}{R}")));
+ this.addAbility(new SpliceAbility(SpliceAbility.ARCANE, "{2}{R}{R}"));
}
private ThroughTheBreach(final ThroughTheBreach card) {
diff --git a/Mage.Sets/src/mage/cards/t/ThunderfootBaloth.java b/Mage.Sets/src/mage/cards/t/ThunderfootBaloth.java
index 3f76d6069d9..8b18562b249 100644
--- a/Mage.Sets/src/mage/cards/t/ThunderfootBaloth.java
+++ b/Mage.Sets/src/mage/cards/t/ThunderfootBaloth.java
@@ -33,7 +33,7 @@ public final class ThunderfootBaloth extends CardImpl {
// Lieutenant - As long as you control your commander, Thunderfoot Baloth gets +2/+2 and other creatures you control get +2/+2 and have trample.
this.addAbility(new LieutenantAbility(new BoostControlledEffect(
2, 2, Duration.WhileOnBattlefield, true
- ), "and other creature you control get +2/+2").addLieutenantEffect(new GainAbilityAllEffect(
+ ), "and other creatures you control get +2/+2").addLieutenantEffect(new GainAbilityAllEffect(
TrampleAbility.getInstance(), Duration.WhileOnBattlefield,
StaticFilters.FILTER_CONTROLLED_CREATURES, true
), "and have trample"));
diff --git a/Mage.Sets/src/mage/cards/t/TidalInfluence.java b/Mage.Sets/src/mage/cards/t/TidalInfluence.java
index e6b62405116..6debbfd6c5f 100644
--- a/Mage.Sets/src/mage/cards/t/TidalInfluence.java
+++ b/Mage.Sets/src/mage/cards/t/TidalInfluence.java
@@ -2,7 +2,6 @@ package mage.cards.t;
import mage.ObjectColor;
import mage.abilities.StateTriggeredAbility;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.CastOnlyIfConditionIsTrueAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
@@ -14,9 +13,13 @@ import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.common.RemoveAllCountersSourceEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
-import mage.constants.*;
+import mage.constants.CardType;
+import mage.constants.ComparisonType;
+import mage.constants.Duration;
+import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
@@ -42,8 +45,8 @@ public final class TidalInfluence extends CardImpl {
private static final Condition conditionCast = new PermanentsOnTheBattlefieldCondition(
filterName, ComparisonType.EQUAL_TO, 0, false);
- private static final Condition condition1 = new SourceHasCounterCondition(CounterType.TIDE, 1, 1);
- private static final Condition condition3 = new SourceHasCounterCondition(CounterType.TIDE, 3, 3);
+ private static final Condition condition1 = new SourceHasCounterCondition(CounterType.TIDE, ComparisonType.EQUAL_TO, 1);
+ private static final Condition condition3 = new SourceHasCounterCondition(CounterType.TIDE, ComparisonType.EQUAL_TO, 3);
public TidalInfluence(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
@@ -62,14 +65,14 @@ public final class TidalInfluence extends CardImpl {
// As long as there is exactly one tide counter on Tidal Influence, all blue creatures get -2/-0.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostAllEffect(-2, -0, Duration.WhileOnBattlefield, filterBlue, false),
- condition1,
- "As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0.")));
+ condition1, "As long as there is exactly one tide counter on {this}, all blue creatures get -2/-0."
+ )));
// As long as there are exactly three tide counters on Tidal Influence, all blue creatures get +2/+0.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, filterBlue, false),
- condition3,
- "As long as there are exactly three tide counter on {this}, all blue creatures get +2/+0.")));
+ condition3, "As long as there are exactly three tide counters on {this}, all blue creatures get +2/+0."
+ )));
// Whenever there are four tide counters on Tidal Influence, remove all tide counters from it.
this.addAbility(new TidalInfluenceTriggeredAbility());
@@ -88,8 +91,8 @@ public final class TidalInfluence extends CardImpl {
class TidalInfluenceTriggeredAbility extends StateTriggeredAbility {
public TidalInfluenceTriggeredAbility() {
- super(Zone.BATTLEFIELD, new RemoveAllCountersSourceEffect(CounterType.TIDE));
- setTriggerPhrase("Whenever there are four tide counters on {this}, ");
+ super(Zone.BATTLEFIELD, new RemoveAllCountersSourceEffect(CounterType.TIDE).setText("remove all tide counters from it"));
+ setTriggerPhrase("Whenever there are four or more tide counters on {this}, ");
}
private TidalInfluenceTriggeredAbility(final TidalInfluenceTriggeredAbility ability) {
@@ -103,6 +106,6 @@ class TidalInfluenceTriggeredAbility extends StateTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- return new CountersSourceCount(CounterType.TIDE).calculate(game, this, null) == 4;
+ return new CountersSourceCount(CounterType.TIDE).calculate(game, this, null) >= 4;
}
}
diff --git a/Mage.Sets/src/mage/cards/t/TimberlineRidge.java b/Mage.Sets/src/mage/cards/t/TimberlineRidge.java
index ebad3e35930..24b5023b754 100644
--- a/Mage.Sets/src/mage/cards/t/TimberlineRidge.java
+++ b/Mage.Sets/src/mage/cards/t/TimberlineRidge.java
@@ -1,50 +1,50 @@
-
package mage.cards.t;
-import java.util.UUID;
-import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.mana.SimpleManaAbility;
+import mage.abilities.mana.GreenManaAbility;
+import mage.abilities.mana.RedManaAbility;
+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 java.util.UUID;
+
/**
- *
* @author Luna Skyrise
*/
public final class TimberlineRidge extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION);
+
public TimberlineRidge(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Timberline Ridge doesn't untap during your untap step if it has a depletion counter on it.
- Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true),
- new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE));
- effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it");
- Ability ability = new SimpleStaticAbility(effect);
- this.addAbility(ability);
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(
+ new DontUntapInControllersUntapStepSourceEffect(false, true), condition
+ ).setText("{this} doesn't untap during your untap step if it has a depletion counter on it")));
+
// At the beginning of your upkeep, remove a depletion counter from Timberline Ridge.
- Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability2);
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance())
+ ));
+
// {tap}: Add {R} or {G}. Put a depletion counter on Timberline Ridge.
- Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(1), new TapSourceCost());
- ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability3);
- Ability ability4 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(1), new TapSourceCost());
- ability4.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability4);
+ Ability ability = new RedManaAbility();
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability);
+ Ability ability2 = new GreenManaAbility();
+ ability2.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability2);
}
private TimberlineRidge(final TimberlineRidge card) {
diff --git a/Mage.Sets/src/mage/cards/t/TimeReaper.java b/Mage.Sets/src/mage/cards/t/TimeReaper.java
index d6a55ec7bcb..3d055d4bbef 100644
--- a/Mage.Sets/src/mage/cards/t/TimeReaper.java
+++ b/Mage.Sets/src/mage/cards/t/TimeReaper.java
@@ -15,7 +15,7 @@ import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.target.common.TargetCardInExile;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -49,7 +49,7 @@ public final class TimeReaper extends CardImpl {
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new PutOnLibraryTargetEffect(false), false, true);
ability.addEffect(new GainLifeEffect(3).concatBy("If you do,")); //I don't think the move can fail? If there's no target then the trigger won't happen
ability.addTarget(new TargetCardInExile(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
ability.withFlavorWord("Consume Anomaly");
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/TimelyWard.java b/Mage.Sets/src/mage/cards/t/TimelyWard.java
index 0e9d9ef01eb..6d52ca741ea 100644
--- a/Mage.Sets/src/mage/cards/t/TimelyWard.java
+++ b/Mage.Sets/src/mage/cards/t/TimelyWard.java
@@ -11,7 +11,10 @@ import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.IndestructibleAbility;
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.filter.FilterPermanent;
import mage.filter.predicate.mageobject.CommanderPredicate;
import mage.target.TargetPermanent;
@@ -38,8 +41,8 @@ public final class TimelyWard extends CardImpl {
this.subtype.add(SubType.AURA);
// You may cast this spell as though it had flash if it targets a commander.
- this.addAbility(new CastAsThoughItHadFlashIfConditionAbility(condition,
- "You may cast {this} as though it had flash if it targets a commander."
+ this.addAbility(new CastAsThoughItHadFlashIfConditionAbility(
+ condition, "You may cast this spell as though it had flash if it targets a commander."
));
// Enchant creature
diff --git a/Mage.Sets/src/mage/cards/t/TinybonesThePickpocket.java b/Mage.Sets/src/mage/cards/t/TinybonesThePickpocket.java
index 3a48422bda3..789c75a5332 100644
--- a/Mage.Sets/src/mage/cards/t/TinybonesThePickpocket.java
+++ b/Mage.Sets/src/mage/cards/t/TinybonesThePickpocket.java
@@ -16,7 +16,7 @@ import mage.filter.FilterCard;
import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -48,7 +48,7 @@ public final class TinybonesThePickpocket extends CardImpl {
OneShotEffect effect = new MayCastTargetCardEffect(CastManaAdjustment.AS_THOUGH_ANY_MANA_TYPE, false);
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetCardInGraveyard(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/ToughCookie.java b/Mage.Sets/src/mage/cards/t/ToughCookie.java
index e7ef120c870..3acbd41f706 100644
--- a/Mage.Sets/src/mage/cards/t/ToughCookie.java
+++ b/Mage.Sets/src/mage/cards/t/ToughCookie.java
@@ -48,10 +48,10 @@ public final class ToughCookie extends CardImpl {
// {2}{G}: Target noncreature artifact you control becomes a 4/4 artifact creature until end of turn.
Ability ability = new SimpleActivatedAbility(new AddCardTypeTargetEffect(
Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE
- ).setText("target noncreature artifact you control becomes"), new ManaCostsImpl<>("{2}{G}"));
+ ).setText("until end of turn, target noncreature artifact you control becomes"), new ManaCostsImpl<>("{2}{G}"));
ability.addEffect(new SetBasePowerToughnessTargetEffect(
4, 4, Duration.EndOfTurn
- ).setText(" a 4/4 artifact creature until end of turn"));
+ ).setText(" a 4/4 artifact creature"));
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
diff --git a/Mage.Sets/src/mage/cards/t/TraxosScourgeOfKroog.java b/Mage.Sets/src/mage/cards/t/TraxosScourgeOfKroog.java
index 11b6b09c7bc..87c266ddf40 100644
--- a/Mage.Sets/src/mage/cards/t/TraxosScourgeOfKroog.java
+++ b/Mage.Sets/src/mage/cards/t/TraxosScourgeOfKroog.java
@@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
-import mage.filter.common.FilterHistoricSpell;
+import mage.filter.StaticFilters;
/**
*
@@ -39,7 +39,7 @@ public final class TraxosScourgeOfKroog extends CardImpl {
ability.addEffect(new DontUntapInControllersUntapStepSourceEffect());
this.addAbility(ability);
// Whenever you cast a historic spell untap Traxos.
- this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), new FilterHistoricSpell(), false));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), StaticFilters.FILTER_SPELL_HISTORIC, false));
}
private TraxosScourgeOfKroog(final TraxosScourgeOfKroog card) {
diff --git a/Mage.Sets/src/mage/cards/t/TriassicEgg.java b/Mage.Sets/src/mage/cards/t/TriassicEgg.java
index fac59e4d996..efb88ddb034 100644
--- a/Mage.Sets/src/mage/cards/t/TriassicEgg.java
+++ b/Mage.Sets/src/mage/cards/t/TriassicEgg.java
@@ -1,10 +1,9 @@
-
package mage.cards.t;
-import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@@ -16,39 +15,39 @@ 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.filter.StaticFilters;
-import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard;
+import java.util.UUID;
+
/**
- *
* @author fireshoes
*/
public final class TriassicEgg extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.HATCHLING, 2);
+
public TriassicEgg(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}");
// {3}, {tap}: Put a hatchling counter on Triassic Egg.
Ability ability = new SimpleActivatedAbility(
- new AddCountersSourceEffect(CounterType.HATCHLING.createInstance(), true),
- new GenericManaCost(3));
+ new AddCountersSourceEffect(CounterType.HATCHLING.createInstance()), new GenericManaCost(3)
+ );
ability.addCost(new TapSourceCost());
this.addAbility(ability);
// Sacrifice Triassic Egg: Choose one - You may put a creature card from your hand onto the battlefield;
- ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD,
+ ability = new ConditionalActivatedAbility(
new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE_A),
- new SacrificeSourceCost(),
- new SourceHasCounterCondition(CounterType.HATCHLING, 2, Integer.MAX_VALUE));
+ new SacrificeSourceCost(), condition
+ ).hideCondition();
+ ability.getModes().setChooseText("Choose one. Activate only if there are two or more hatchling counters on {this}.");
// or return target creature card from your graveyard to the battlefield. Activate this ability only if two or more hatchling counters are on Triassic Egg.
- Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect());
- Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD);
- mode.addTarget(target);
- ability.addMode(mode);
+ ability.addMode(new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect())
+ .addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/t/TrygonPredator.java b/Mage.Sets/src/mage/cards/t/TrygonPredator.java
index c3d22b61ee4..40cff196c1c 100644
--- a/Mage.Sets/src/mage/cards/t/TrygonPredator.java
+++ b/Mage.Sets/src/mage/cards/t/TrygonPredator.java
@@ -12,7 +12,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactOrEnchantmentPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -36,7 +36,7 @@ public final class TrygonPredator extends CardImpl {
// Whenever Trygon Predator deals combat damage to a player, you may destroy target artifact or enchantment that player controls.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DestroyTargetEffect(), true, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/u/UriangerAugurelt.java b/Mage.Sets/src/mage/cards/u/UriangerAugurelt.java
new file mode 100644
index 00000000000..a72e0d4c91d
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/u/UriangerAugurelt.java
@@ -0,0 +1,155 @@
+package mage.cards.u;
+
+import mage.MageIdentifier;
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.PlayLandOrCastSpellFromExileTriggeredAbility;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.effects.AsThoughEffectImpl;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.GainLifeEffect;
+import mage.abilities.effects.common.asthought.MayLookAtTargetCardEffect;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.game.Controllable;
+import mage.game.Game;
+import mage.players.Player;
+import mage.target.targetpointer.FixedTarget;
+import mage.util.CardUtil;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class UriangerAugurelt extends CardImpl {
+
+ public UriangerAugurelt(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}");
+
+ this.supertype.add(SuperType.LEGENDARY);
+ this.subtype.add(SubType.ELF);
+ this.subtype.add(SubType.ADVISOR);
+ this.power = new MageInt(1);
+ this.toughness = new MageInt(3);
+
+ // Whenever you play a land from exile or cast a spell from exile, you gain 2 life.
+ this.addAbility(new PlayLandOrCastSpellFromExileTriggeredAbility(new GainLifeEffect(2)));
+
+ // Draw Arcanum -- {T}: Look at the top card of your library. You may exile it face down.
+ this.addAbility(new SimpleActivatedAbility(
+ new UriangerAugureltExileEffect(), new TapSourceCost()
+ ).withFlavorWord("Draw Arcanum"));
+
+ // Play Arcanum -- {T}: Until end of turn, you may play cards exiled with Urianger Augurelt. Spells you cast this way cost {2} less to cast.
+ this.addAbility(new SimpleActivatedAbility(
+ new UriangerAugureltPlayEffect(), new TapSourceCost()
+ ).setIdentifier(MageIdentifier.UriangerAugureltAlternateCast).withFlavorWord("Play Arcanum"));
+ }
+
+ private UriangerAugurelt(final UriangerAugurelt card) {
+ super(card);
+ }
+
+ @Override
+ public UriangerAugurelt copy() {
+ return new UriangerAugurelt(this);
+ }
+}
+
+class UriangerAugureltExileEffect extends OneShotEffect {
+
+ UriangerAugureltExileEffect() {
+ super(Outcome.Benefit);
+ staticText = "look at the top card of your library. You may exile it face down";
+ }
+
+ private UriangerAugureltExileEffect(final UriangerAugureltExileEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public UriangerAugureltExileEffect copy() {
+ return new UriangerAugureltExileEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player player = game.getPlayer(source.getControllerId());
+ if (player == null) {
+ return false;
+ }
+ Card card = player.getLibrary().getFromTop(game);
+ if (card == null) {
+ return false;
+ }
+ player.lookAtCards("Top card of library", card, game);
+ if (!player.chooseUse(Outcome.DrawCard, "Exile " + card.getLogName() + " face down?", source, game)) {
+ return false;
+ }
+ player.moveCardsToExile(
+ card, source, game, false,
+ CardUtil.getExileZoneId(game, source),
+ CardUtil.getSourceName(game, source)
+ );
+ card.setFaceDown(true, game);
+ game.addEffect(new MayLookAtTargetCardEffect(source.getControllerId())
+ .setTargetPointer(new FixedTarget(card, game)), source);
+ return true;
+ }
+}
+
+class UriangerAugureltPlayEffect extends AsThoughEffectImpl {
+
+ UriangerAugureltPlayEffect() {
+ super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
+ Duration.EndOfTurn, Outcome.AIDontUseIt);
+ staticText = "until end of turn, you may play cards exiled " +
+ "with {this}. Spells you cast this way cost {2} less to cast";
+ }
+
+ private UriangerAugureltPlayEffect(final UriangerAugureltPlayEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public UriangerAugureltPlayEffect copy() {
+ return new UriangerAugureltPlayEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ return true;
+ }
+
+ @Override
+ public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
+ if (!source.isControlledBy(affectedControllerId)) {
+ return false;
+ }
+ Card card = game.getCard(objectId);
+ if (card == null || !Optional
+ .ofNullable(CardUtil.getExileZoneId(game, source))
+ .map(game.getState().getExile()::getExileZone)
+ .filter(e -> e.contains(objectId))
+ .isPresent()) {
+ return false;
+ }
+ if (card.isLand(game)) {
+ return true;
+ }
+ // TODO: This should ideally apply the reduction while the spell is being cast because effects that increase the cost apply first
+ Optional.ofNullable(source)
+ .map(Controllable::getControllerId)
+ .map(game::getPlayer)
+ .ifPresent(player -> player.setCastSourceIdWithAlternateMana(
+ card.getId(), CardUtil.reduceCost(card.getManaCost(), 2),
+ null, MageIdentifier.UriangerAugureltAlternateCast
+ ));
+ return true;
+ }
+}
diff --git a/Mage.Sets/src/mage/cards/u/UrzasTome.java b/Mage.Sets/src/mage/cards/u/UrzasTome.java
index 7d33e6178d9..919ae0dd24a 100644
--- a/Mage.Sets/src/mage/cards/u/UrzasTome.java
+++ b/Mage.Sets/src/mage/cards/u/UrzasTome.java
@@ -12,8 +12,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
-import mage.constants.Zone;
-import mage.filter.common.FilterHistoricCard;
+import mage.filter.FilterCard;
+import mage.filter.predicate.mageobject.HistoricPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInYourGraveyard;
@@ -25,11 +25,17 @@ import java.util.UUID;
*/
public final class UrzasTome extends CardImpl {
+ private static final FilterCard filter = new FilterCard("historic card");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
+
public UrzasTome(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}");
// {3}, {T}: Draw a card. Then discard a card unless you exile a historic card from your graveyard.
- Ability ability = new SimpleActivatedAbility(new UrzasTomeEffect(), new GenericManaCost(3));
+ Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(3));
+ ability.addEffect(new UrzasTomeEffect());
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
@@ -46,9 +52,14 @@ public final class UrzasTome extends CardImpl {
class UrzasTomeEffect extends OneShotEffect {
+ private static final FilterCard filter = new FilterCard("a historic card");
+ static {
+ filter.add(HistoricPredicate.instance);
+ }
+
UrzasTomeEffect() {
super(Outcome.Discard);
- staticText = "Draw a card. Then discard a card unless you exile a historic card from your graveyard";
+ staticText = "Then discard a card unless you exile a historic card from your graveyard";
}
private UrzasTomeEffect(final UrzasTomeEffect effect) {
@@ -63,20 +74,17 @@ class UrzasTomeEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
- new DrawCardSourceControllerEffect(1).apply(game, source);
- if (controller != null
- && controller.chooseUse(Outcome.Exile, "Exile a historic card from your graveyard?", source, game)) {
- Cost cost = new ExileFromGraveCost(new TargetCardInYourGraveyard(new FilterHistoricCard()));
- if (cost.canPay(source, source, controller.getId(), game)) {
- if (cost.pay(source, game, source, controller.getId(), false, null)) {
- return true;
- }
+ if (controller == null) {
+ return false;
+ }
+ if (controller.chooseUse(Outcome.Exile, "Exile a historic card from your graveyard?", source, game)) {
+ Cost cost = new ExileFromGraveCost(new TargetCardInYourGraveyard(filter));
+ if (cost.canPay(source, source, controller.getId(), game)
+ && cost.pay(source, game, source, controller.getId(), false, null)) {
+ return true;
}
}
- if (controller != null) {
- controller.discard(1, false, false, source, game);
- return true;
- }
- return false;
+ controller.discard(1, false, false, source, game);
+ return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/v/VadrokApexOfThunder.java b/Mage.Sets/src/mage/cards/v/VadrokApexOfThunder.java
index 8983c563218..cfc26c54b96 100644
--- a/Mage.Sets/src/mage/cards/v/VadrokApexOfThunder.java
+++ b/Mage.Sets/src/mage/cards/v/VadrokApexOfThunder.java
@@ -11,7 +11,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
-import mage.filter.common.FilterNoncreatureCard;
+import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.common.TargetCardInYourGraveyard;
@@ -22,11 +22,12 @@ import java.util.UUID;
*/
public final class VadrokApexOfThunder extends CardImpl {
- private static final FilterCard filter = new FilterNoncreatureCard(
+ private static final FilterCard filter = new FilterCard(
"noncreature card with mana value 3 or less from your graveyard"
);
static {
+ filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
}
diff --git a/Mage.Sets/src/mage/cards/v/ValleyFloodcaller.java b/Mage.Sets/src/mage/cards/v/ValleyFloodcaller.java
index 093df79bfed..c29f61e1303 100644
--- a/Mage.Sets/src/mage/cards/v/ValleyFloodcaller.java
+++ b/Mage.Sets/src/mage/cards/v/ValleyFloodcaller.java
@@ -18,7 +18,6 @@ import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
-import mage.filter.common.FilterNoncreatureCard;
import mage.filter.predicate.Predicates;
/**
@@ -27,12 +26,13 @@ import mage.filter.predicate.Predicates;
*/
public final class ValleyFloodcaller extends CardImpl {
- private static final FilterCard nonCreatureFilter = new FilterNoncreatureCard("noncreature spells");
+ private static final FilterCard nonCreatureFilter = new FilterCard("noncreature spells");
private static final FilterCreaturePermanent creatureFilter =
new FilterCreaturePermanent("Birds, Frogs, Otters, and Rats");
static {
+ nonCreatureFilter.add(Predicates.not(CardType.CREATURE.getPredicate()));
creatureFilter.add(TargetController.YOU.getControllerPredicate());
creatureFilter.add(Predicates.or(
SubType.BIRD.getPredicate(),
diff --git a/Mage.Sets/src/mage/cards/v/Veldt.java b/Mage.Sets/src/mage/cards/v/Veldt.java
index 14b9ec804e3..d12518abd5c 100644
--- a/Mage.Sets/src/mage/cards/v/Veldt.java
+++ b/Mage.Sets/src/mage/cards/v/Veldt.java
@@ -1,50 +1,50 @@
-
package mage.cards.v;
-import java.util.UUID;
-import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
-import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect;
-import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
-import mage.abilities.mana.SimpleManaAbility;
+import mage.abilities.mana.GreenManaAbility;
+import mage.abilities.mana.WhiteManaAbility;
+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 java.util.UUID;
+
/**
- *
* @author Luna Skyrise
*/
public final class Veldt extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.DEPLETION);
+
public Veldt(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},"");
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// Veldt doesn't untap during your untap step if it has a depletion counter on it.
- Effect effect = new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(false, true),
- new SourceHasCounterCondition(CounterType.DEPLETION, 1, Integer.MAX_VALUE));
- effect.setText("{this} doesn't untap during your untap step if it has a depletion counter on it");
- Ability ability = new SimpleStaticAbility(effect);
- this.addAbility(ability);
+ this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect(
+ new DontUntapInControllersUntapStepSourceEffect(false, true), condition
+ ).setText("{this} doesn't untap during your untap step if it has a depletion counter on it")));
+
// At the beginning of your upkeep, remove a depletion counter from Veldt.
- Ability ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability2);
+ this.addAbility(new BeginningOfUpkeepTriggeredAbility(
+ new RemoveCounterSourceEffect(CounterType.DEPLETION.createInstance())
+ ));
+
// {tap}: Add {G} or {W}. Put a depletion counter on Veldt.
- Ability ability3 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.GreenMana(1), new TapSourceCost());
- ability3.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability3);
- Ability ability4 = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.WhiteMana(1), new TapSourceCost());
- ability4.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
- this.addAbility(ability4);
+ Ability ability = new GreenManaAbility();
+ ability.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability);
+ Ability ability2 = new WhiteManaAbility();
+ ability2.addEffect(new AddCountersSourceEffect(CounterType.DEPLETION.createInstance()));
+ this.addAbility(ability2);
}
private Veldt(final Veldt card) {
diff --git a/Mage.Sets/src/mage/cards/v/VentifactBottle.java b/Mage.Sets/src/mage/cards/v/VentifactBottle.java
index 6c7c1114d21..8e21b814cdc 100644
--- a/Mage.Sets/src/mage/cards/v/VentifactBottle.java
+++ b/Mage.Sets/src/mage/cards/v/VentifactBottle.java
@@ -1,23 +1,20 @@
-
package mage.cards.v;
import mage.Mana;
import mage.abilities.Ability;
-import mage.abilities.TriggeredAbility;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
-import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
+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.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
+import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
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.game.Game;
import mage.game.permanent.Permanent;
@@ -30,22 +27,20 @@ import java.util.UUID;
*/
public final class VentifactBottle extends CardImpl {
+ private static final Condition condition = new SourceHasCounterCondition(CounterType.CHARGE);
+
public VentifactBottle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {X}{1}, {tap}: Put X charge counters on Ventifact Bottle. Activate this ability only any time you could cast a sorcery.
- Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD,
- new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), GetXValue.instance, true),
- new ManaCostsImpl<>("{X}{1}"));
+ Ability ability = new ActivateAsSorceryActivatedAbility(new AddCountersSourceEffect(
+ CounterType.CHARGE.createInstance(), GetXValue.instance, true
+ ), new ManaCostsImpl<>("{X}{1}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
+
// At the beginning of your precombat main phase, if Ventifact Bottle has a charge counter on it, tap it and remove all charge counters from it. Add {C} for each charge counter removed this way.
- TriggeredAbility ability2 = new BeginningOfFirstMainTriggeredAbility(new VentifactBottleEffect());
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2,
- new SourceHasCounterCondition(CounterType.CHARGE, 1, Integer.MAX_VALUE),
- "At the beginning of your first main phase, "
- + "if {this} has a charge counter on it, tap it and remove all charge counters from it. "
- + "Add {C} for each charge counter removed this way."));
+ this.addAbility(new BeginningOfFirstMainTriggeredAbility(new VentifactBottleEffect()).withInterveningIf(condition));
}
private VentifactBottle(final VentifactBottle card) {
@@ -62,6 +57,7 @@ class VentifactBottleEffect extends OneShotEffect {
VentifactBottleEffect() {
super(Outcome.Benefit);
+ staticText = "tap it and remove all charge counters from it. Add {C} for each charge counter removed this way";
}
private VentifactBottleEffect(final VentifactBottleEffect effect) {
@@ -75,16 +71,16 @@ class VentifactBottleEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Player player = game.getPlayer(source.getControllerId());
- if (sourcePermanent != null && player != null) {
- int amountRemoved = sourcePermanent.removeAllCounters(CounterType.CHARGE.getName(), source, game);
- sourcePermanent.tap(source, game);
- Mana mana = new Mana();
- mana.setColorless(amountRemoved);
- player.getManaPool().addMana(mana, game, source);
- return true;
+ Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
+ if (player == null || sourcePermanent == null) {
+ return false;
}
- return false;
+ sourcePermanent.tap(source, game);
+ int amountRemoved = sourcePermanent.removeAllCounters(CounterType.CHARGE.getName(), source, game);
+ if (amountRemoved > 0) {
+ player.getManaPool().addMana(Mana.ColorlessMana(amountRemoved), game, source);
+ }
+ return true;
}
}
diff --git a/Mage.Sets/src/mage/cards/v/VoyagerGlidecar.java b/Mage.Sets/src/mage/cards/v/VoyagerGlidecar.java
index 5131996f87e..36386420cea 100644
--- a/Mage.Sets/src/mage/cards/v/VoyagerGlidecar.java
+++ b/Mage.Sets/src/mage/cards/v/VoyagerGlidecar.java
@@ -17,7 +17,10 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.counters.CounterType;
-import mage.filter.StaticFilters;
+import mage.filter.common.FilterControlledCreaturePermanent;
+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;
@@ -27,6 +30,13 @@ import java.util.UUID;
*/
public final class VoyagerGlidecar extends CardImpl {
+ private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("other untapped creatures you control");
+
+ static {
+ filter.add(AnotherPredicate.instance);
+ filter.add(TappedPredicate.UNTAPPED);
+ }
+
public VoyagerGlidecar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{W}");
@@ -42,9 +52,7 @@ public final class VoyagerGlidecar extends CardImpl {
new AddCardTypeSourceEffect(
Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE
).setText("until end of turn, this Vehicle becomes an artifact creature"),
- new TapTargetCost(new TargetControlledPermanent(
- 3, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES
- ))
+ new TapTargetCost(new TargetControlledPermanent(3, filter))
);
ability.addEffect(new GainAbilitySourceEffect(
FlyingAbility.getInstance(), Duration.EndOfTurn
diff --git a/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java b/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java
index 90ca31c8068..081b584c775 100644
--- a/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java
+++ b/Mage.Sets/src/mage/cards/v/VrenTheRelentless.java
@@ -2,15 +2,16 @@ package mage.cards.v;
import mage.MageInt;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.replacement.CreaturesAreExiledOnDeathReplacementEffect;
+import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.WardAbility;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
@@ -31,6 +32,10 @@ import java.util.UUID;
*/
public final class VrenTheRelentless extends CardImpl {
+ private static final Hint hint = new ValueHint(
+ "Creatures exiled under opponents' control this turn", VrenTheRelentlessCount.instance
+ );
+
public VrenTheRelentless(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}");
this.supertype.add(SuperType.LEGENDARY);
@@ -49,11 +54,8 @@ public final class VrenTheRelentless extends CardImpl {
// At the beginning of each end step, create X 1/1 black Rat creature tokens with "This creature gets +1/+1 for each
// other Rat you control," where X is the number of creatures your opponents controlled that were exiled this turn.
this.addAbility(new BeginningOfEndStepTriggeredAbility(
- TargetController.ANY, new CreateTokenEffect(new VrenRatToken(), VrenTheRelentlessCount.instance)
- .setText("create X 1/1 black Rat creature tokens with \"This creature gets +1/+1 for each other Rat you " +
- "control,\" where X is the number of creatures your opponents controlled that were exiled this turn"),
- false
- ).addHint(new ValueHint("Creatures exiled under opponents' control this turn", VrenTheRelentlessCount.instance)), new VrenTheRelentlessWatcher());
+ TargetController.ANY, new CreateTokenEffect(new VrenRatToken(), VrenTheRelentlessCount.instance), false
+ ).addHint(hint), new VrenTheRelentlessWatcher());
}
private VrenTheRelentless(final VrenTheRelentless card) {
@@ -72,7 +74,7 @@ enum VrenTheRelentlessCount implements DynamicValue {
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
VrenTheRelentlessWatcher watcher = game.getState().getWatcher(VrenTheRelentlessWatcher.class);
- return watcher == null ? 0 : watcher.getCount(sourceAbility.getControllerId());
+ return watcher == null ? 0 : watcher.getCount(sourceAbility.getControllerId(), game);
}
@Override
@@ -80,9 +82,14 @@ enum VrenTheRelentlessCount implements DynamicValue {
return instance;
}
+ @Override
+ public String toString() {
+ return "X";
+ }
+
@Override
public String getMessage() {
- return "";
+ return "the number of creatures that were exiled under your opponents' control this turn";
}
}
@@ -100,7 +107,9 @@ class VrenTheRelentlessWatcher extends Watcher {
return;
}
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
- if ((zEvent.getToZone() == Zone.EXILED && zEvent.getFromZone() == Zone.BATTLEFIELD) && zEvent.getTarget().isCreature(game)) {
+ if (zEvent.getToZone() == Zone.EXILED
+ && zEvent.getFromZone() == Zone.BATTLEFIELD
+ && zEvent.getTarget().isCreature(game)) {
playerMap.compute(zEvent.getTarget().getControllerId(), CardUtil::setOrIncrementValue);
}
}
@@ -111,10 +120,11 @@ class VrenTheRelentlessWatcher extends Watcher {
super.reset();
}
- int getCount(UUID playerId) {
- return playerMap.entrySet().stream()
- .filter(entry -> !entry.getKey().equals(playerId))
- .mapToInt(Map.Entry::getValue)
+ int getCount(UUID playerId, Game game) {
+ return game
+ .getOpponents(playerId)
+ .stream()
+ .mapToInt(uuid -> playerMap.getOrDefault(uuid, 0))
.sum();
}
}
diff --git a/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java b/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java
index a1b9525baf1..ee721ad93cf 100644
--- a/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java
+++ b/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java
@@ -33,7 +33,7 @@ public final class WaxmaneBaku extends CardImpl {
this.toughness = new MageInt(2);
// Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Waxmane Baku.
- this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
// {1}, Remove X ki counters from Waxmane Baku: Tap X target creatures.
Ability ability = new SimpleActivatedAbility(new TapTargetEffect("tap X target creatures"), new GenericManaCost(1));
diff --git a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java
index ff2009b7210..7a7a03a5c22 100644
--- a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java
+++ b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java
@@ -17,8 +17,8 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.token.custom.CreatureToken;
+import mage.util.CardUtil;
-import java.util.Objects;
import java.util.UUID;
/**
@@ -65,11 +65,8 @@ enum WeatherseedTotemCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
- return source
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("permanentWasCreature"))
- .filter(Objects::nonNull)
- .anyMatch(Boolean.class::cast);
+ return CardUtil
+ .getEffectValueFromAbility(source, "permanentWasCreature", Boolean.class)
+ .orElse(false);
}
}
diff --git a/Mage.Sets/src/mage/cards/w/WinterCursedRider.java b/Mage.Sets/src/mage/cards/w/WinterCursedRider.java
index c2fea8bd0f0..82eeb2ae7c5 100644
--- a/Mage.Sets/src/mage/cards/w/WinterCursedRider.java
+++ b/Mage.Sets/src/mage/cards/w/WinterCursedRider.java
@@ -24,6 +24,7 @@ import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
+import mage.util.CardUtil;
/**
*
@@ -54,7 +55,7 @@ public final class WinterCursedRider extends CardImpl {
WardAbility wardAbility = new WardAbility(new PayLifeCost(2));
this.addAbility(new SimpleStaticAbility(
new GainAbilityAllEffect(wardAbility, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS)
- .setText("Artifacts you control have " + "\"" + wardAbility.getRuleWithoutHint() + "\"")
+ .setText("Artifacts you control have " + "\"" + CardUtil.getTextWithFirstCharUpperCase(wardAbility.getRuleWithoutHint()) + "\"")
));
// Exhaust -- {2}{U}{B}, {T}, Exile X artifact cards from your graveyard: Each other nonartifact creature gets -X/-X until end of turn.
Ability ability = new ExhaustAbility(new BoostAllEffect(xValue, xValue, Duration.EndOfTurn, filter, true),
diff --git a/Mage.Sets/src/mage/cards/w/WoebringerDemon.java b/Mage.Sets/src/mage/cards/w/WoebringerDemon.java
index 8917bdf355a..26dbfd48dea 100644
--- a/Mage.Sets/src/mage/cards/w/WoebringerDemon.java
+++ b/Mage.Sets/src/mage/cards/w/WoebringerDemon.java
@@ -55,7 +55,7 @@ class WoebringerDemonEffect extends OneShotEffect {
WoebringerDemonEffect() {
super(Outcome.Detriment);
- this.staticText = "that player sacrifices a creature. If the player can't, sacrifice {this}";
+ this.staticText = "that player sacrifices a creature of their choice. If the player can't, sacrifice {this}";
}
private WoebringerDemonEffect(final WoebringerDemonEffect effect) {
diff --git a/Mage.Sets/src/mage/cards/w/WoodlandChampion.java b/Mage.Sets/src/mage/cards/w/WoodlandChampion.java
index 7ccea61836b..50f57ff6a06 100644
--- a/Mage.Sets/src/mage/cards/w/WoodlandChampion.java
+++ b/Mage.Sets/src/mage/cards/w/WoodlandChampion.java
@@ -89,7 +89,7 @@ class WoodlandChampionTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
- return "Whenever one or more tokens enter the battlefield under your control, " +
+ return "Whenever one or more tokens you control enter, " +
"put that many +1/+1 counters on {this}.";
}
}
diff --git a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java
index 15a2c841e0b..d4ccc426dc2 100644
--- a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java
+++ b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java
@@ -17,7 +17,7 @@ import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -50,7 +50,7 @@ public final class WrexialTheRisenDeep extends CardImpl {
+ ThatSpellGraveyardExileReplacementEffect.RULE_A);
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false, true);
ability.addTarget(new TargetCardInGraveyard(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/cards/y/YukiOnna.java b/Mage.Sets/src/mage/cards/y/YukiOnna.java
index cd765b28e73..b47c617e53e 100644
--- a/Mage.Sets/src/mage/cards/y/YukiOnna.java
+++ b/Mage.Sets/src/mage/cards/y/YukiOnna.java
@@ -32,7 +32,7 @@ public final class YukiOnna extends CardImpl {
ability.addTarget(new TargetArtifactPermanent());
this.addAbility(ability);
// Whenever you cast a Spirit or Arcane spell, you may return Yuki-Onna to its owner's hand.
- this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true));
+ this.addAbility(new SpellCastControllerTriggeredAbility(new ReturnToHandSourceEffect(true), StaticFilters.FILTER_SPELL_SPIRIT_OR_ARCANE, true));
}
private YukiOnna(final YukiOnna card) {
diff --git a/Mage.Sets/src/mage/cards/z/ZarethSanTheTrickster.java b/Mage.Sets/src/mage/cards/z/ZarethSanTheTrickster.java
index a40f80a5084..057fe6af878 100644
--- a/Mage.Sets/src/mage/cards/z/ZarethSanTheTrickster.java
+++ b/Mage.Sets/src/mage/cards/z/ZarethSanTheTrickster.java
@@ -22,7 +22,7 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetControlledPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -61,7 +61,7 @@ public final class ZarethSanTheTrickster extends CardImpl {
// Whenever Zareth San deals combat damage to a player, you may put target permanent card from that player's graveyard onto the battlefield under your control.
Ability ability2 = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true, true);
ability2.addTarget(new TargetCardInGraveyard(filterCardGraveyard));
- ability2.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability2.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability2);
}
diff --git a/Mage.Sets/src/mage/cards/z/ZombieCannibal.java b/Mage.Sets/src/mage/cards/z/ZombieCannibal.java
index d2bac983887..ad8c8915e03 100644
--- a/Mage.Sets/src/mage/cards/z/ZombieCannibal.java
+++ b/Mage.Sets/src/mage/cards/z/ZombieCannibal.java
@@ -12,7 +12,7 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.target.common.TargetCardInGraveyard;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
import java.util.UUID;
@@ -34,7 +34,7 @@ public final class ZombieCannibal extends CardImpl {
Effect effect = new ExileTargetEffect(null, "", Zone.GRAVEYARD);
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, true, true);
ability.addTarget(new TargetCardInGraveyard(filterGraveyardCard));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster(true));
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster(true));
this.addAbility(ability);
}
diff --git a/Mage.Sets/src/mage/sets/AssassinsCreed.java b/Mage.Sets/src/mage/sets/AssassinsCreed.java
index 5925cca943d..56755d60e15 100644
--- a/Mage.Sets/src/mage/sets/AssassinsCreed.java
+++ b/Mage.Sets/src/mage/sets/AssassinsCreed.java
@@ -237,9 +237,9 @@ public final class AssassinsCreed extends ExpansionSet {
cards.add(new SetCardInfo("Poison-Blade Mentor", 288, Rarity.UNCOMMON, mage.cards.p.PoisonBladeMentor.class));
cards.add(new SetCardInfo("Propaganda", 195, Rarity.UNCOMMON, mage.cards.p.Propaganda.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Propaganda", 85, Rarity.UNCOMMON, mage.cards.p.Propaganda.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Ratonhnhake:ton", 150, Rarity.RARE, mage.cards.r.Ratonhnhaketon.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Ratonhnhake:ton", 244, Rarity.RARE, mage.cards.r.Ratonhnhaketon.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Ratonhnhake:ton", 62, Rarity.RARE, mage.cards.r.Ratonhnhakton.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Ratonhnhaketon", 150, Rarity.RARE, mage.cards.r.Ratonhnhaketon.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Ratonhnhaketon", 244, Rarity.RARE, mage.cards.r.Ratonhnhaketon.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Ratonhnhaketon", 62, Rarity.RARE, mage.cards.r.Ratonhnhaketon.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Raven Clan War-Axe", 297, Rarity.RARE, mage.cards.r.RavenClanWarAxe.class));
cards.add(new SetCardInfo("Reconnaissance", 179, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Reconnaissance", 82, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java
index a789aee7419..76a45438046 100644
--- a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java
+++ b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java
@@ -206,9 +206,9 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Cloudkill", 121, Rarity.UNCOMMON, mage.cards.c.Cloudkill.class));
cards.add(new SetCardInfo("Colossal Badger", 223, Rarity.COMMON, mage.cards.c.ColossalBadger.class));
cards.add(new SetCardInfo("Command Tower", 351, Rarity.COMMON, mage.cards.c.CommandTower.class));
- //cards.add(new SetCardInfo("Commander Liara Portyr", 270, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Commander Liara Portyr", 418, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Commander Liara Portyr", 529, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Commander Liara Portyr", 270, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Commander Liara Portyr", 418, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Commander Liara Portyr", 529, Rarity.UNCOMMON, mage.cards.c.CommanderLiaraPortyr.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Compulsive Research", 715, Rarity.COMMON, mage.cards.c.CompulsiveResearch.class));
cards.add(new SetCardInfo("Cone of Cold", 61, Rarity.UNCOMMON, mage.cards.c.ConeOfCold.class));
cards.add(new SetCardInfo("Consuming Aberration", 840, Rarity.RARE, mage.cards.c.ConsumingAberration.class));
@@ -571,8 +571,8 @@ public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet {
cards.add(new SetCardInfo("Mindblade Render", 762, Rarity.RARE, mage.cards.m.MindbladeRender.class));
cards.add(new SetCardInfo("Mindcrank", 866, Rarity.UNCOMMON, mage.cards.m.Mindcrank.class));
cards.add(new SetCardInfo("Minimus Containment", 34, Rarity.COMMON, mage.cards.m.MinimusContainment.class));
- //cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 285, Rarity.MYTHIC, mage.cards.m.MinscAndBooTimelessHeroes.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 363, Rarity.MYTHIC, mage.cards.m.MinscAndBooTimelessHeroes.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 285, Rarity.MYTHIC, mage.cards.m.MinscBooTimelessHeroes.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 363, Rarity.MYTHIC, mage.cards.m.MinscBooTimelessHeroes.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Minthara, Merciless Soul", 286, Rarity.UNCOMMON, mage.cards.m.MintharaMercilessSoul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Minthara, Merciless Soul", 432, Rarity.UNCOMMON, mage.cards.m.MintharaMercilessSoul.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Minthara, Merciless Soul", 543, Rarity.UNCOMMON, mage.cards.m.MintharaMercilessSoul.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage.Sets/src/mage/sets/DoctorWho.java b/Mage.Sets/src/mage/sets/DoctorWho.java
index a7eec56c7bf..e90aca9d94d 100644
--- a/Mage.Sets/src/mage/sets/DoctorWho.java
+++ b/Mage.Sets/src/mage/sets/DoctorWho.java
@@ -295,10 +295,10 @@ public final class DoctorWho extends ExpansionSet {
cards.add(new SetCardInfo("Ensnared by the Mara", 689, Rarity.RARE, mage.cards.e.EnsnaredByTheMara.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ensnared by the Mara", 84, Rarity.RARE, mage.cards.e.EnsnaredByTheMara.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ensnared by the Mara", 975, Rarity.RARE, mage.cards.e.EnsnaredByTheMara.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Everybody Lives!", 18, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Everybody Lives!", 338, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Everybody Lives!", 623, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("Everybody Lives!", 929, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Everybody Lives!", 18, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Everybody Lives!", 338, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Everybody Lives!", 623, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Everybody Lives!", 929, Rarity.RARE, mage.cards.e.EverybodyLives.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Everything Comes to Dust", 19, Rarity.RARE, mage.cards.e.EverythingComesToDust.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Everything Comes to Dust", 339, Rarity.RARE, mage.cards.e.EverythingComesToDust.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Everything Comes to Dust", 624, Rarity.RARE, mage.cards.e.EverythingComesToDust.class, NON_FULL_USE_VARIOUS));
@@ -877,8 +877,8 @@ public final class DoctorWho extends ExpansionSet {
cards.add(new SetCardInfo("The Caves of Androzani", 15, Rarity.RARE, mage.cards.t.TheCavesOfAndrozani.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Caves of Androzani", 620, Rarity.RARE, mage.cards.t.TheCavesOfAndrozani.class, NON_FULL_USE_VARIOUS));
//cards.add(new SetCardInfo("The Cheetah Planet", 574, Rarity.COMMON, mage.cards.t.TheCheetahPlanet.class));
- //cards.add(new SetCardInfo("The Curse of Fenric", 118, Rarity.RARE, mage.cards.t.TheCurseOfFenric.class, NON_FULL_USE_VARIOUS));
- //cards.add(new SetCardInfo("The Curse of Fenric", 723, Rarity.RARE, mage.cards.t.TheCurseOfFenric.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("The Curse of Fenric", 118, Rarity.RARE, mage.cards.t.TheCurseOfFenric.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("The Curse of Fenric", 723, Rarity.RARE, mage.cards.t.TheCurseOfFenric.class, NON_FULL_USE_VARIOUS));
//cards.add(new SetCardInfo("The Cyber-Controller", 119, Rarity.RARE, mage.cards.t.TheCyberController.class, NON_FULL_USE_VARIOUS));
//cards.add(new SetCardInfo("The Cyber-Controller", 405, Rarity.RARE, mage.cards.t.TheCyberController.class, NON_FULL_USE_VARIOUS));
//cards.add(new SetCardInfo("The Cyber-Controller", 724, Rarity.RARE, mage.cards.t.TheCyberController.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java
index bbcb0411918..18abe25f7d0 100644
--- a/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java
+++ b/Mage.Sets/src/mage/sets/DuskmournHouseOfHorror.java
@@ -278,6 +278,9 @@ public final class DuskmournHouseOfHorror extends ExpansionSet {
cards.add(new SetCardInfo("Razorkin Needlehead", 153, Rarity.RARE, mage.cards.r.RazorkinNeedlehead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Razorkin Needlehead", 347, Rarity.RARE, mage.cards.r.RazorkinNeedlehead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Razortrap Gorge", 267, Rarity.COMMON, mage.cards.r.RazortrapGorge.class));
+ 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("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));
@@ -366,7 +369,9 @@ public final class DuskmournHouseOfHorror extends ExpansionSet {
cards.add(new SetCardInfo("Valgavoth's Lair", 327, Rarity.RARE, mage.cards.v.ValgavothsLair.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Valgavoth's Onslaught", 204, Rarity.RARE, mage.cards.v.ValgavothsOnslaught.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Valgavoth's Onslaught", 324, Rarity.RARE, mage.cards.v.ValgavothsOnslaught.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Valgavoth, Terror Eater", 120, Rarity.MYTHIC, mage.cards.v.ValgavothTerrorEater.class));
+ cards.add(new SetCardInfo("Valgavoth, Terror Eater", 120, Rarity.MYTHIC, mage.cards.v.ValgavothTerrorEater.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Valgavoth, Terror Eater", 352, Rarity.MYTHIC, mage.cards.v.ValgavothTerrorEater.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Valgavoth, Terror Eater", 407, Rarity.MYTHIC, mage.cards.v.ValgavothTerrorEater.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vanish from Sight", 82, Rarity.COMMON, mage.cards.v.VanishFromSight.class));
cards.add(new SetCardInfo("Vengeful Possession", 162, Rarity.UNCOMMON, mage.cards.v.VengefulPossession.class));
cards.add(new SetCardInfo("Veteran Survivor", 40, Rarity.UNCOMMON, mage.cards.v.VeteranSurvivor.class));
diff --git a/Mage.Sets/src/mage/sets/EternalWeekend.java b/Mage.Sets/src/mage/sets/EternalWeekend.java
index 093c5bd439c..fd66aed343f 100644
--- a/Mage.Sets/src/mage/sets/EternalWeekend.java
+++ b/Mage.Sets/src/mage/sets/EternalWeekend.java
@@ -26,6 +26,8 @@ public class EternalWeekend extends ExpansionSet {
cards.add(new SetCardInfo("Gush", "2022a", Rarity.RARE, mage.cards.g.Gush.class, RETRO_ART));
cards.add(new SetCardInfo("Mental Misstep", "2023a", Rarity.RARE, mage.cards.m.MentalMisstep.class, RETRO_ART));
cards.add(new SetCardInfo("Ponder", "2022b", Rarity.RARE, mage.cards.p.Ponder.class, RETRO_ART));
+ cards.add(new SetCardInfo("Tendrils of Agony", "2025a", Rarity.RARE, mage.cards.t.TendrilsOfAgony.class, RETRO_ART));
cards.add(new SetCardInfo("Tinker", "2024a", Rarity.MYTHIC, mage.cards.t.Tinker.class, RETRO_ART));
+ cards.add(new SetCardInfo("Trinisphere", "2025b", Rarity.MYTHIC, mage.cards.t.Trinisphere.class, RETRO_ART));
}
}
diff --git a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java
index 876bb9a61d8..cf475f0bf0d 100644
--- a/Mage.Sets/src/mage/sets/FinalFantasyCommander.java
+++ b/Mage.Sets/src/mage/sets/FinalFantasyCommander.java
@@ -226,6 +226,8 @@ public final class FinalFantasyCommander extends ExpansionSet {
cards.add(new SetCardInfo("Krile Baldesion", 86, Rarity.RARE, mage.cards.k.KrileBaldesion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Legions to Ashes", 326, Rarity.RARE, mage.cards.l.LegionsToAshes.class));
cards.add(new SetCardInfo("Lethal Scheme", 277, Rarity.RARE, mage.cards.l.LethalScheme.class));
+ cards.add(new SetCardInfo("Lifestream's Blessing", 122, Rarity.RARE, mage.cards.l.LifestreamsBlessing.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Lifestream's Blessing", 67, Rarity.RARE, mage.cards.l.LifestreamsBlessing.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Greaves", 349, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class));
cards.add(new SetCardInfo("Lingering Souls", 245, Rarity.UNCOMMON, mage.cards.l.LingeringSouls.class));
cards.add(new SetCardInfo("Locke, Treasure Hunter", 177, Rarity.RARE, mage.cards.l.LockeTreasureHunter.class, NON_FULL_USE_VARIOUS));
@@ -342,6 +344,8 @@ public final class FinalFantasyCommander extends ExpansionSet {
cards.add(new SetCardInfo("Spire of Industry", 426, Rarity.RARE, mage.cards.s.SpireOfIndustry.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));
+ cards.add(new SetCardInfo("Strago and Relm", 59, Rarity.RARE, mage.cards.s.StragoAndRelm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sublime Epiphany", 271, Rarity.RARE, mage.cards.s.SublimeEpiphany.class));
cards.add(new SetCardInfo("Sulfurous Springs", 427, Rarity.RARE, mage.cards.s.SulfurousSprings.class));
cards.add(new SetCardInfo("Summon: Esper Valigarmanda", 198, Rarity.RARE, mage.cards.s.SummonEsperValigarmanda.class, NON_FULL_USE_VARIOUS));
@@ -427,6 +431,8 @@ public final class FinalFantasyCommander extends ExpansionSet {
cards.add(new SetCardInfo("Umaro, Raging Yeti", 63, Rarity.RARE, mage.cards.u.UmaroRagingYeti.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Underground River", 439, Rarity.RARE, mage.cards.u.UndergroundRiver.class));
cards.add(new SetCardInfo("Unfinished Business", 259, Rarity.RARE, mage.cards.u.UnfinishedBusiness.class));
+ cards.add(new SetCardInfo("Urianger Augurelt", 189, Rarity.RARE, mage.cards.u.UriangerAugurelt.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Urianger Augurelt", 96, Rarity.RARE, mage.cards.u.UriangerAugurelt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Vandalblast", 298, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class));
cards.add(new SetCardInfo("Vanquish the Horde", 260, Rarity.RARE, mage.cards.v.VanquishTheHorde.class));
cards.add(new SetCardInfo("Vincent, Vengeful Atoner", 157, Rarity.RARE, mage.cards.v.VincentVengefulAtoner.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage.Sets/src/mage/sets/Mirage.java b/Mage.Sets/src/mage/sets/Mirage.java
index dbb7bbc88a4..a35daacfe45 100644
--- a/Mage.Sets/src/mage/sets/Mirage.java
+++ b/Mage.Sets/src/mage/sets/Mirage.java
@@ -96,7 +96,7 @@ public final class Mirage extends ExpansionSet {
cards.add(new SetCardInfo("Decomposition", 212, Rarity.UNCOMMON, mage.cards.d.Decomposition.class, RETRO_ART));
cards.add(new SetCardInfo("Delirium", 260, Rarity.UNCOMMON, mage.cards.d.Delirium.class, RETRO_ART));
cards.add(new SetCardInfo("Dirtwater Wraith", 117, Rarity.COMMON, mage.cards.d.DirtwaterWraith.class, RETRO_ART));
-// cards.add(new SetCardInfo("Discordant Spirit", 261, Rarity.RARE, mage.cards.d.DiscordantSpirit.class, RETRO_ART));
+ cards.add(new SetCardInfo("Discordant Spirit", 261, Rarity.RARE, mage.cards.d.DiscordantSpirit.class, RETRO_ART));
cards.add(new SetCardInfo("Disempower", 9, Rarity.COMMON, mage.cards.d.Disempower.class, RETRO_ART));
cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class, RETRO_ART));
cards.add(new SetCardInfo("Dissipate", 61, Rarity.UNCOMMON, mage.cards.d.Dissipate.class, RETRO_ART));
@@ -302,7 +302,7 @@ public final class Mirage extends ExpansionSet {
cards.add(new SetCardInfo("Shauku, Endbringer", 142, Rarity.RARE, mage.cards.s.ShaukuEndbringer.class, RETRO_ART));
cards.add(new SetCardInfo("Shimmer", 92, Rarity.RARE, mage.cards.s.Shimmer.class, RETRO_ART));
cards.add(new SetCardInfo("Sidar Jabari", 39, Rarity.RARE, mage.cards.s.SidarJabari.class, RETRO_ART));
-// cards.add(new SetCardInfo("Sirocco", 192, Rarity.UNCOMMON, mage.cards.s.Sirocco.class, RETRO_ART));
+ cards.add(new SetCardInfo("Sirocco", 192, Rarity.UNCOMMON, mage.cards.s.Sirocco.class, RETRO_ART));
cards.add(new SetCardInfo("Skulking Ghost", 143, Rarity.COMMON, mage.cards.s.SkulkingGhost.class, RETRO_ART));
cards.add(new SetCardInfo("Sky Diamond", 319, Rarity.UNCOMMON, mage.cards.s.SkyDiamond.class, RETRO_ART));
cards.add(new SetCardInfo("Soar", 93, Rarity.COMMON, mage.cards.s.Soar.class, RETRO_ART));
diff --git a/Mage.Sets/src/mage/sets/RavnicaClueEdition.java b/Mage.Sets/src/mage/sets/RavnicaClueEdition.java
index 9b71bfb42a0..6111eb31787 100644
--- a/Mage.Sets/src/mage/sets/RavnicaClueEdition.java
+++ b/Mage.Sets/src/mage/sets/RavnicaClueEdition.java
@@ -43,7 +43,7 @@ public final class RavnicaClueEdition extends ExpansionSet {
cards.add(new SetCardInfo("Boros Garrison", 231, Rarity.COMMON, mage.cards.b.BorosGarrison.class));
cards.add(new SetCardInfo("Boros Guildgate", 232, Rarity.COMMON, mage.cards.b.BorosGuildgate.class));
cards.add(new SetCardInfo("Boros Signet", 220, Rarity.COMMON, mage.cards.b.BorosSignet.class));
- //cards.add(new SetCardInfo("Boros Strike-Captain", 25, Rarity.RARE, mage.cards.b.BorosStrikeCaptain.class));
+ cards.add(new SetCardInfo("Boros Strike-Captain", 25, Rarity.RARE, mage.cards.b.BorosStrikeCaptain.class));
cards.add(new SetCardInfo("Breeding Pool", 275, Rarity.RARE, mage.cards.b.BreedingPool.class));
cards.add(new SetCardInfo("Candlestick", 8, Rarity.UNCOMMON, mage.cards.c.Candlestick.class));
cards.add(new SetCardInfo("Carnage Interpreter", 26, Rarity.RARE, mage.cards.c.CarnageInterpreter.class));
@@ -64,7 +64,7 @@ public final class RavnicaClueEdition extends ExpansionSet {
cards.add(new SetCardInfo("Corpse Churn", 107, Rarity.COMMON, mage.cards.c.CorpseChurn.class));
cards.add(new SetCardInfo("Cosmotronic Wave", 129, Rarity.COMMON, mage.cards.c.CosmotronicWave.class));
cards.add(new SetCardInfo("Council's Judgment", 57, Rarity.RARE, mage.cards.c.CouncilsJudgment.class));
- //cards.add(new SetCardInfo("Covetous Elegy", 29, Rarity.RARE, mage.cards.c.CovetousElegy.class));
+ cards.add(new SetCardInfo("Covetous Elegy", 29, Rarity.RARE, mage.cards.c.CovetousElegy.class));
cards.add(new SetCardInfo("Curse of Chains", 183, Rarity.COMMON, mage.cards.c.CurseOfChains.class));
cards.add(new SetCardInfo("Dagger Caster", 130, Rarity.UNCOMMON, mage.cards.d.DaggerCaster.class));
cards.add(new SetCardInfo("Daggerclaw Imp", 108, Rarity.UNCOMMON, mage.cards.d.DaggerclawImp.class));
@@ -107,7 +107,7 @@ public final class RavnicaClueEdition extends ExpansionSet {
cards.add(new SetCardInfo("Fresh-Faced Recruit", 192, Rarity.COMMON, mage.cards.f.FreshFacedRecruit.class));
cards.add(new SetCardInfo("Frostburn Weird", 193, Rarity.COMMON, mage.cards.f.FrostburnWeird.class));
cards.add(new SetCardInfo("Fungal Rebirth", 163, Rarity.UNCOMMON, mage.cards.f.FungalRebirth.class));
- //cards.add(new SetCardInfo("Furious Spinesplitter", 33, Rarity.UNCOMMON, mage.cards.f.FuriousSpinesplitter.class));
+ cards.add(new SetCardInfo("Furious Spinesplitter", 33, Rarity.UNCOMMON, mage.cards.f.FuriousSpinesplitter.class));
cards.add(new SetCardInfo("Giant Adephage", 164, Rarity.MYTHIC, mage.cards.g.GiantAdephage.class));
cards.add(new SetCardInfo("Gift of Strength", 165, Rarity.COMMON, mage.cards.g.GiftOfStrength.class));
cards.add(new SetCardInfo("Glorifier of Dusk", 62, Rarity.UNCOMMON, mage.cards.g.GlorifierOfDusk.class));
@@ -168,14 +168,14 @@ public final class RavnicaClueEdition extends ExpansionSet {
cards.add(new SetCardInfo("Master Biomancer", 200, Rarity.MYTHIC, mage.cards.m.MasterBiomancer.class));
cards.add(new SetCardInfo("Mastermind Plum", 3, Rarity.RARE, mage.cards.m.MastermindPlum.class));
cards.add(new SetCardInfo("Mausoleum Turnkey", 116, Rarity.UNCOMMON, mage.cards.m.MausoleumTurnkey.class));
- //cards.add(new SetCardInfo("Memory Vampire", 38, Rarity.RARE, mage.cards.m.MemoryVampire.class));
+ cards.add(new SetCardInfo("Memory Vampire", 38, Rarity.RARE, mage.cards.m.MemoryVampire.class));
cards.add(new SetCardInfo("Mighty Leap", 66, Rarity.COMMON, mage.cards.m.MightyLeap.class));
cards.add(new SetCardInfo("Mountain", 266, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 267, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 268, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 269, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Nissa's Judgment", 170, Rarity.UNCOMMON, mage.cards.n.NissasJudgment.class));
- //cards.add(new SetCardInfo("Ordruun Mentor", 39, Rarity.UNCOMMON, mage.cards.o.OrdruunMentor.class));
+ cards.add(new SetCardInfo("Ordruun Mentor", 39, Rarity.UNCOMMON, mage.cards.o.OrdruunMentor.class));
cards.add(new SetCardInfo("Ornery Goblin", 143, Rarity.COMMON, mage.cards.o.OrneryGoblin.class));
cards.add(new SetCardInfo("Orzhov Basilica", 241, Rarity.COMMON, mage.cards.o.OrzhovBasilica.class));
cards.add(new SetCardInfo("Orzhov Guildgate", 242, Rarity.COMMON, mage.cards.o.OrzhovGuildgate.class));
@@ -210,7 +210,7 @@ public final class RavnicaClueEdition extends ExpansionSet {
cards.add(new SetCardInfo("Reduce to Ashes", 145, Rarity.COMMON, mage.cards.r.ReduceToAshes.class));
cards.add(new SetCardInfo("Repeal", 94, Rarity.COMMON, mage.cards.r.Repeal.class));
cards.add(new SetCardInfo("Rescuer Sphinx", 95, Rarity.UNCOMMON, mage.cards.r.RescuerSphinx.class));
- //cards.add(new SetCardInfo("Resonance Technician", 41, Rarity.RARE, mage.cards.r.ResonanceTechnician.class));
+ cards.add(new SetCardInfo("Resonance Technician", 41, Rarity.RARE, mage.cards.r.ResonanceTechnician.class));
cards.add(new SetCardInfo("Ribbons of Night", 120, Rarity.UNCOMMON, mage.cards.r.RibbonsOfNight.class));
cards.add(new SetCardInfo("Ripscale Predator", 146, Rarity.COMMON, mage.cards.r.RipscalePredator.class));
cards.add(new SetCardInfo("Roaming Ghostlight", 96, Rarity.COMMON, mage.cards.r.RoamingGhostlight.class));
diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java
index c6eb9f9e797..6e0085ed7b0 100644
--- a/Mage.Sets/src/mage/sets/SecretLairDrop.java
+++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java
@@ -38,7 +38,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Reaper King", 9, Rarity.MYTHIC, mage.cards.r.ReaperKing.class));
cards.add(new SetCardInfo("Sliver Overlord", 10, Rarity.MYTHIC, mage.cards.s.SliverOverlord.class));
cards.add(new SetCardInfo("The Ur-Dragon", 11, Rarity.MYTHIC, mage.cards.t.TheUrDragon.class));
- cards.add(new SetCardInfo("Bitterblossom", 12, Rarity.MYTHIC, mage.cards.b.Bitterblossom.class));
+ cards.add(new SetCardInfo("Bitterblossom", 12, Rarity.MYTHIC, mage.cards.b.Bitterblossom.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Goblin Bushwhacker", 17, Rarity.RARE, mage.cards.g.GoblinBushwhacker.class));
cards.add(new SetCardInfo("Goblin Sharpshooter", 18, Rarity.RARE, mage.cards.g.GoblinSharpshooter.class));
cards.add(new SetCardInfo("Goblin King", 19, Rarity.RARE, mage.cards.g.GoblinKing.class, NON_FULL_USE_VARIOUS));
@@ -101,7 +101,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Mogis, God of Slaughter", 78, Rarity.MYTHIC, mage.cards.m.MogisGodOfSlaughter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Keranos, God of Storms", 79, Rarity.MYTHIC, mage.cards.k.KeranosGodOfStorms.class));
cards.add(new SetCardInfo("Nylea, God of the Hunt", 80, Rarity.MYTHIC, mage.cards.n.NyleaGodOfTheHunt.class));
- cards.add(new SetCardInfo("Xenagos, God of Revels", 81, Rarity.MYTHIC, mage.cards.x.XenagosGodOfRevels.class));
+ cards.add(new SetCardInfo("Xenagos, God of Revels", 81, Rarity.MYTHIC, mage.cards.x.XenagosGodOfRevels.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Pharika, God of Affliction", 82, Rarity.MYTHIC, mage.cards.p.PharikaGodOfAffliction.class));
cards.add(new SetCardInfo("Lightning Bolt", 83, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Bolt", 84, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS));
@@ -170,9 +170,9 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Malik, Grim Manipulator", 147, Rarity.MYTHIC, mage.cards.m.MalikGrimManipulator.class));
cards.add(new SetCardInfo("Admonition Angel", 154, Rarity.MYTHIC, mage.cards.a.AdmonitionAngel.class));
cards.add(new SetCardInfo("Roil Elemental", 155, Rarity.RARE, mage.cards.r.RoilElemental.class));
- cards.add(new SetCardInfo("Zulaport Cutthroat", 156, Rarity.RARE, mage.cards.z.ZulaportCutthroat.class));
+ cards.add(new SetCardInfo("Zulaport Cutthroat", 156, Rarity.RARE, mage.cards.z.ZulaportCutthroat.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Warren Instigator", 157, Rarity.MYTHIC, mage.cards.w.WarrenInstigator.class));
- cards.add(new SetCardInfo("Avenger of Zendikar", 158, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class));
+ cards.add(new SetCardInfo("Avenger of Zendikar", 158, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonlord Belzenlok", 159, Rarity.MYTHIC, mage.cards.d.DemonlordBelzenlok.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Demonlord Belzenlok", "159*", Rarity.MYTHIC, mage.cards.d.DemonlordBelzenlok.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Griselbrand", 160, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS));
@@ -198,7 +198,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Decree of Pain", 187, Rarity.RARE, mage.cards.d.DecreeOfPain.class));
cards.add(new SetCardInfo("Gamble", 188, Rarity.RARE, mage.cards.g.Gamble.class));
cards.add(new SetCardInfo("Nature's Lore", 189, Rarity.RARE, mage.cards.n.NaturesLore.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Soul-Scar Mage", 190, Rarity.RARE, mage.cards.s.SoulScarMage.class));
+ cards.add(new SetCardInfo("Soul-Scar Mage", 190, Rarity.RARE, mage.cards.s.SoulScarMage.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dryad of the Ilysian Grove", 191, Rarity.RARE, mage.cards.d.DryadOfTheIlysianGrove.class));
cards.add(new SetCardInfo("Sakura-Tribe Elder", 192, Rarity.RARE, mage.cards.s.SakuraTribeElder.class));
cards.add(new SetCardInfo("Spell Queller", 193, Rarity.RARE, mage.cards.s.SpellQueller.class));
@@ -212,7 +212,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Chromatic Lantern", 202, Rarity.RARE, mage.cards.c.ChromaticLantern.class));
cards.add(new SetCardInfo("Commander's Sphere", 203, Rarity.RARE, mage.cards.c.CommandersSphere.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Darksteel Ingot", 204, Rarity.RARE, mage.cards.d.DarksteelIngot.class));
- cards.add(new SetCardInfo("Gilded Lotus", 205, Rarity.RARE, mage.cards.g.GildedLotus.class));
+ cards.add(new SetCardInfo("Gilded Lotus", 205, Rarity.RARE, mage.cards.g.GildedLotus.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Exquisite Blood", 206, Rarity.RARE, mage.cards.e.ExquisiteBlood.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Night's Whisper", 207, Rarity.RARE, mage.cards.n.NightsWhisper.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Phyrexian Tower", 208, Rarity.RARE, mage.cards.p.PhyrexianTower.class));
@@ -223,7 +223,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Vorinclex, Voice of Hunger", 213, Rarity.MYTHIC, mage.cards.v.VorinclexVoiceOfHunger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Heliod, Sun-Crowned", 214, Rarity.MYTHIC, mage.cards.h.HeliodSunCrowned.class));
cards.add(new SetCardInfo("Goblin Rabblemaster", 215, Rarity.RARE, mage.cards.g.GoblinRabblemaster.class));
- cards.add(new SetCardInfo("Monastery Swiftspear", 216, Rarity.RARE, mage.cards.m.MonasterySwiftspear.class));
+ cards.add(new SetCardInfo("Monastery Swiftspear", 216, Rarity.RARE, mage.cards.m.MonasterySwiftspear.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Boros Charm", 217, Rarity.RARE, mage.cards.b.BorosCharm.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Gisela, Blade of Goldnight", 218, Rarity.MYTHIC, mage.cards.g.GiselaBladeOfGoldnight.class));
cards.add(new SetCardInfo("Frost Titan", 220, Rarity.MYTHIC, mage.cards.f.FrostTitan.class));
@@ -366,7 +366,7 @@ public class SecretLairDrop extends ExpansionSet {
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));
- cards.add(new SetCardInfo("Chain Lightning", 370, Rarity.RARE, mage.cards.c.ChainLightning.class));
+ 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("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));
@@ -472,7 +472,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Depala, Pilot Exemplar", 464, Rarity.RARE, mage.cards.d.DepalaPilotExemplar.class));
cards.add(new SetCardInfo("Nomad Outpost", 465, Rarity.RARE, mage.cards.n.NomadOutpost.class));
cards.add(new SetCardInfo("Island", 466, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
- cards.add(new SetCardInfo("Concordant Crossroads", 467, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class));
+ cards.add(new SetCardInfo("Concordant Crossroads", 467, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghost Quarter", 468, Rarity.RARE, mage.cards.g.GhostQuarter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ash Barrens", 469, Rarity.RARE, mage.cards.a.AshBarrens.class));
cards.add(new SetCardInfo("Command Beacon", 470, Rarity.RARE, mage.cards.c.CommandBeacon.class, NON_FULL_USE_VARIOUS));
@@ -495,7 +495,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Mountain", 487, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 488, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Akroma, Angel of Wrath", 489, Rarity.MYTHIC, mage.cards.a.AkromaAngelOfWrath.class));
- cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 490, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class));
+ cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 490, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Glissa Sunseeker", 491, Rarity.RARE, mage.cards.g.GlissaSunseeker.class));
cards.add(new SetCardInfo("Olivia, Mobilized for War", 492, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kozilek, the Great Distortion", 493, Rarity.MYTHIC, mage.cards.k.KozilekTheGreatDistortion.class));
@@ -631,11 +631,11 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Basal Sliver", 629, Rarity.RARE, mage.cards.b.BasalSliver.class));
cards.add(new SetCardInfo("Dregscape Sliver", 631, Rarity.RARE, mage.cards.d.DregscapeSliver.class));
cards.add(new SetCardInfo("Leeching Sliver", 632, Rarity.RARE, mage.cards.l.LeechingSliver.class));
- cards.add(new SetCardInfo("Plague Sliver", 633, Rarity.RARE, mage.cards.p.PlagueSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plague Sliver", "633Ph", Rarity.RARE, mage.cards.p.PlagueSliver.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Plague Sliver", 633, Rarity.RARE, mage.cards.p.PlagueSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Syphon Sliver", 634, Rarity.RARE, mage.cards.s.SyphonSliver.class));
- cards.add(new SetCardInfo("Toxin Sliver", 635, Rarity.RARE, mage.cards.t.ToxinSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Toxin Sliver", "635Ph", Rarity.RARE, mage.cards.t.ToxinSliver.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Toxin Sliver", 635, Rarity.RARE, mage.cards.t.ToxinSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Belligerent Sliver", 636, Rarity.RARE, mage.cards.b.BelligerentSliver.class));
cards.add(new SetCardInfo("Blur Sliver", 637, Rarity.RARE, mage.cards.b.BlurSliver.class));
cards.add(new SetCardInfo("Fury Sliver", 638, Rarity.RARE, mage.cards.f.FurySliver.class));
@@ -657,8 +657,8 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Quick Sliver", 655, Rarity.RARE, mage.cards.q.QuickSliver.class));
cards.add(new SetCardInfo("Root Sliver", 656, Rarity.RARE, mage.cards.r.RootSliver.class));
cards.add(new SetCardInfo("Tempered Sliver", 657, Rarity.RARE, mage.cards.t.TemperedSliver.class));
- cards.add(new SetCardInfo("Virulent Sliver", 659, Rarity.RARE, mage.cards.v.VirulentSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Virulent Sliver", "659Ph", Rarity.RARE, mage.cards.v.VirulentSliver.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Virulent Sliver", 659, Rarity.RARE, mage.cards.v.VirulentSliver.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Cloudshredder Sliver", 660, Rarity.RARE, mage.cards.c.CloudshredderSliver.class));
cards.add(new SetCardInfo("Crystalline Sliver", 661, Rarity.RARE, mage.cards.c.CrystallineSliver.class));
cards.add(new SetCardInfo("Frenetic Sliver", 662, Rarity.RARE, mage.cards.f.FreneticSliver.class));
@@ -680,8 +680,8 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Torbran, Thane of Red Fell", 678, Rarity.RARE, mage.cards.t.TorbranThaneOfRedFell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ghost Quarter", 679, Rarity.RARE, mage.cards.g.GhostQuarter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowborn Apostle", 680, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Shadowborn Apostle", 681, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowborn Apostle", "681Ph", Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Shadowborn Apostle", 681, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowborn Apostle", 682, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowborn Apostle", 683, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Shadowborn Apostle", 684, Rarity.RARE, mage.cards.s.ShadowbornApostle.class, NON_FULL_USE_VARIOUS));
@@ -734,7 +734,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Seraph Sanctuary", 733, Rarity.RARE, mage.cards.s.SeraphSanctuary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Grima Wormtongue", 734, Rarity.RARE, mage.cards.g.GrimaWormtongue.class));
cards.add(new SetCardInfo("Gaea's Blessing", 735, Rarity.RARE, mage.cards.g.GaeasBlessing.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Colossus Hammer", 736, Rarity.RARE, mage.cards.c.ColossusHammer.class));
+ cards.add(new SetCardInfo("Colossus Hammer", 736, Rarity.RARE, mage.cards.c.ColossusHammer.class, NON_FULL_USE_VARIOUS));
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));
@@ -811,17 +811,19 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Seven Dwarves", 813, Rarity.RARE, mage.cards.s.SevenDwarves.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seven Dwarves", 814, Rarity.RARE, mage.cards.s.SevenDwarves.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seven Dwarves", 815, Rarity.RARE, mage.cards.s.SevenDwarves.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Seven Dwarves", 816, Rarity.RARE, mage.cards.s.SevenDwarves.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arcane Signet", 820, Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Arcane Signet", "820*", Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Echo of Eons", 821, Rarity.RARE, mage.cards.e.EchoOfEons.class, RETRO_ART));
cards.add(new SetCardInfo("Hive Mind", 822, Rarity.RARE, mage.cards.h.HiveMind.class, RETRO_ART));
cards.add(new SetCardInfo("Chaos Warp", 823, Rarity.RARE, mage.cards.c.ChaosWarp.class, RETRO_ART_USE_VARIOUS));
cards.add(new SetCardInfo("Evolving Wilds", 824, Rarity.RARE, mage.cards.e.EvolvingWilds.class, RETRO_ART_USE_VARIOUS));
- cards.add(new SetCardInfo("Goblin Bombardment", 825, Rarity.RARE, mage.cards.g.GoblinBombardment.class));
+ cards.add(new SetCardInfo("Goblin Bombardment", 825, Rarity.RARE, mage.cards.g.GoblinBombardment.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kezzerdrix", 826, Rarity.RARE, mage.cards.k.Kezzerdrix.class));
cards.add(new SetCardInfo("Norin the Wary", 827, Rarity.RARE, mage.cards.n.NorinTheWary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Norin the Wary", "827b", Rarity.RARE, mage.cards.n.NorinTheWary.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Keen Duelist", 828, Rarity.RARE, mage.cards.k.KeenDuelist.class));
+ cards.add(new SetCardInfo("Fatestitcher", 835, Rarity.RARE, mage.cards.f.Fatestitcher.class, RETRO_ART));
cards.add(new SetCardInfo("Champion of the Perished", 837, Rarity.RARE, mage.cards.c.ChampionOfThePerished.class, RETRO_ART));
cards.add(new SetCardInfo("Corpse Connoisseur", 838, Rarity.RARE, mage.cards.c.CorpseConnoisseur.class, RETRO_ART));
cards.add(new SetCardInfo("Cryptbreaker", 839, Rarity.RARE, mage.cards.c.Cryptbreaker.class, RETRO_ART));
@@ -831,13 +833,16 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Haakon, Stromgald Scourge", 843, Rarity.RARE, mage.cards.h.HaakonStromgaldScourge.class, RETRO_ART));
cards.add(new SetCardInfo("Headless Rider", 844, Rarity.RARE, mage.cards.h.HeadlessRider.class, RETRO_ART));
cards.add(new SetCardInfo("Liliana's Standard Bearer", 845, Rarity.RARE, mage.cards.l.LilianasStandardBearer.class, RETRO_ART));
+ cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 846, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class, RETRO_ART_USE_VARIOUS));
cards.add(new SetCardInfo("Pontiff of Blight", 848, Rarity.RARE, mage.cards.p.PontiffOfBlight.class, RETRO_ART));
cards.add(new SetCardInfo("Ravenous Rotbelly", 849, Rarity.RARE, mage.cards.r.RavenousRotbelly.class, RETRO_ART));
cards.add(new SetCardInfo("Relentless Dead", 850, Rarity.MYTHIC, mage.cards.r.RelentlessDead.class, RETRO_ART));
+ cards.add(new SetCardInfo("Rotting Regisaur", 852, Rarity.RARE, mage.cards.r.RottingRegisaur.class, RETRO_ART));
cards.add(new SetCardInfo("Tomb Tyrant", 854, Rarity.RARE, mage.cards.t.TombTyrant.class, RETRO_ART));
cards.add(new SetCardInfo("Tormod, the Desecrator", 855, Rarity.RARE, mage.cards.t.TormodTheDesecrator.class, RETRO_ART));
cards.add(new SetCardInfo("Vindictive Lich", 856, Rarity.RARE, mage.cards.v.VindictiveLich.class, RETRO_ART_USE_VARIOUS));
cards.add(new SetCardInfo("Diregraf Captain", 858, Rarity.RARE, mage.cards.d.DiregrafCaptain.class, RETRO_ART));
+ cards.add(new SetCardInfo("Havengul Lich", 859, Rarity.MYTHIC, mage.cards.h.HavengulLich.class, RETRO_ART));
cards.add(new SetCardInfo("Nekusar, the Mindrazer", 860, Rarity.MYTHIC, mage.cards.n.NekusarTheMindrazer.class, RETRO_ART_USE_VARIOUS));
cards.add(new SetCardInfo("Varina, Lich Queen", 861, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class, RETRO_ART_USE_VARIOUS));
cards.add(new SetCardInfo("Wilhelt, the Rotcleaver", 862, Rarity.MYTHIC, mage.cards.w.WilheltTheRotcleaver.class, RETRO_ART));
@@ -852,18 +857,20 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Yargle and Multani", 872, Rarity.RARE, mage.cards.y.YargleAndMultani.class));
cards.add(new SetCardInfo("Dark Deal", 873, Rarity.RARE, mage.cards.d.DarkDeal.class));
cards.add(new SetCardInfo("Archivist of Oghma", 874, Rarity.RARE, mage.cards.a.ArchivistOfOghma.class));
- cards.add(new SetCardInfo("Battle Angels of Tyr", 875, Rarity.RARE, mage.cards.b.BattleAngelsOfTyr.class));
+ cards.add(new SetCardInfo("Battle Angels of Tyr", 875, Rarity.MYTHIC, mage.cards.b.BattleAngelsOfTyr.class));
cards.add(new SetCardInfo("Xorn", 876, Rarity.RARE, mage.cards.x.Xorn.class));
cards.add(new SetCardInfo("Druid of Purification", 877, Rarity.RARE, mage.cards.d.DruidOfPurification.class));
cards.add(new SetCardInfo("Prosperous Innkeeper", 878, Rarity.RARE, mage.cards.p.ProsperousInnkeeper.class));
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("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("Changeling Outcast", 894, Rarity.RARE, mage.cards.c.ChangelingOutcast.class));
cards.add(new SetCardInfo("Helpful Hunter", 895, Rarity.RARE, mage.cards.h.HelpfulHunter.class));
cards.add(new SetCardInfo("Spirited Companion", 896, Rarity.RARE, mage.cards.s.SpiritedCompanion.class));
cards.add(new SetCardInfo("The Scarab God", 900, Rarity.MYTHIC, mage.cards.t.TheScarabGod.class));
@@ -874,6 +881,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Ignoble Hierarch", 906, Rarity.RARE, mage.cards.i.IgnobleHierarch.class));
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("Elspeth, Knight-Errant", 1001, Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Patron Wizard", 1002, Rarity.RARE, mage.cards.p.PatronWizard.class));
@@ -896,10 +904,10 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Idyllic Tutor", 1020, Rarity.RARE, mage.cards.i.IdyllicTutor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swords to Plowshares", 1021, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Solve the Equation", 1022, Rarity.RARE, mage.cards.s.SolveTheEquation.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Praetor's Grasp", 1023, Rarity.RARE, mage.cards.p.PraetorsGrasp.class));
+ cards.add(new SetCardInfo("Praetor's Grasp", 1023, Rarity.RARE, mage.cards.p.PraetorsGrasp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Veil of Summer", 1024, Rarity.RARE, mage.cards.v.VeilOfSummer.class));
cards.add(new SetCardInfo("Merciless Executioner", 1025, Rarity.RARE, mage.cards.m.MercilessExecutioner.class));
- cards.add(new SetCardInfo("Aggravated Assault", 1026, Rarity.RARE, mage.cards.a.AggravatedAssault.class));
+ cards.add(new SetCardInfo("Aggravated Assault", 1026, Rarity.RARE, mage.cards.a.AggravatedAssault.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Krenko, Tin Street Kingpin", 1027, Rarity.RARE, mage.cards.k.KrenkoTinStreetKingpin.class));
cards.add(new SetCardInfo("Zurgo Helmsmasher", 1028, Rarity.MYTHIC, mage.cards.z.ZurgoHelmsmasher.class));
cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 1029, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class));
@@ -972,7 +980,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Deepglow Skate", 1093, Rarity.RARE, mage.cards.d.DeepglowSkate.class));
cards.add(new SetCardInfo("Tireless Tracker", 1094, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Contagion Engine", 1095, Rarity.RARE, mage.cards.c.ContagionEngine.class));
- cards.add(new SetCardInfo("Sword of Truth and Justice", 1096, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class));
+ cards.add(new SetCardInfo("Sword of Truth and Justice", 1096, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Laboratory Maniac", 1097, Rarity.RARE, mage.cards.l.LaboratoryManiac.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Stitcher's Supplier", 1098, Rarity.RARE, mage.cards.s.StitchersSupplier.class));
cards.add(new SetCardInfo("Beast Whisperer", 1099, Rarity.RARE, mage.cards.b.BeastWhisperer.class));
@@ -1168,7 +1176,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Grand Abolisher", 1285, Rarity.RARE, mage.cards.g.GrandAbolisher.class));
cards.add(new SetCardInfo("Selfless Savior", 1286, Rarity.RARE, mage.cards.s.SelflessSavior.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Akroma, Angel of Fury", 1287, Rarity.MYTHIC, mage.cards.a.AkromaAngelOfFury.class));
- cards.add(new SetCardInfo("Umezawa's Jitte", 1288, Rarity.RARE, mage.cards.u.UmezawasJitte.class));
+ cards.add(new SetCardInfo("Umezawa's Jitte", 1288, Rarity.RARE, mage.cards.u.UmezawasJitte.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Linvala, Keeper of Silence", 1289, Rarity.MYTHIC, mage.cards.l.LinvalaKeeperOfSilence.class));
cards.add(new SetCardInfo("Sunblast Angel", 1290, Rarity.RARE, mage.cards.s.SunblastAngel.class));
cards.add(new SetCardInfo("Emeria, the Sky Ruin", 1291, Rarity.RARE, mage.cards.e.EmeriaTheSkyRuin.class));
@@ -1346,7 +1354,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Fynn, the Fangbearer", 1449, Rarity.RARE, mage.cards.f.FynnTheFangbearer.class));
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));
+ 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));
@@ -1527,7 +1535,7 @@ 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));
+ 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));
@@ -1540,7 +1548,7 @@ public class SecretLairDrop extends ExpansionSet {
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.RARE, 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("Obeka, Brute Chronologist", "1579*", Rarity.RARE, mage.cards.o.ObekaBruteChronologist.class, NON_FULL_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));
@@ -1686,7 +1694,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Ruhan of the Fomori", 1695, Rarity.MYTHIC, mage.cards.r.RuhanOfTheFomori.class));
cards.add(new SetCardInfo("Sol Ring", 1696, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Command Tower", 1697, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Sorin Markov", 1698, Rarity.RARE, mage.cards.s.SorinMarkov.class));
+ cards.add(new SetCardInfo("Sorin Markov", 1698, Rarity.MYTHIC, mage.cards.s.SorinMarkov.class));
cards.add(new SetCardInfo("Huatli, Radiant Champion", 1699, Rarity.MYTHIC, mage.cards.h.HuatliRadiantChampion.class));
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));
@@ -1700,7 +1708,7 @@ public class SecretLairDrop extends ExpansionSet {
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));
+ 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));
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));
@@ -1737,7 +1745,7 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Black Panther, Wakandan King", 1747, Rarity.MYTHIC, mage.cards.b.BlackPantherWakandanKing.class));
cards.add(new SetCardInfo("Secure the Wastes", 1748, Rarity.RARE, mage.cards.s.SecureTheWastes.class));
cards.add(new SetCardInfo("Primal Vigor", 1749, Rarity.RARE, mage.cards.p.PrimalVigor.class, NON_FULL_USE_VARIOUS));
- cards.add(new SetCardInfo("Heroic Intervention", 1750, Rarity.RARE, mage.cards.h.HeroicIntervention.class));
+ cards.add(new SetCardInfo("Heroic Intervention", 1750, Rarity.RARE, mage.cards.h.HeroicIntervention.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Karn's Bastion", 1751, Rarity.RARE, mage.cards.k.KarnsBastion.class));
cards.add(new SetCardInfo("Deadly Rollick", 1754, Rarity.RARE, mage.cards.d.DeadlyRollick.class));
cards.add(new SetCardInfo("Saw in Half", 1755, Rarity.RARE, mage.cards.s.SawInHalf.class));
@@ -1799,7 +1807,7 @@ public class SecretLairDrop extends ExpansionSet {
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));
+ 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));
@@ -1834,6 +1842,21 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Crib Swap", 1850, Rarity.UNCOMMON, mage.cards.c.CribSwap.class));
cards.add(new SetCardInfo("Homeward Path", 1851, Rarity.RARE, mage.cards.h.HomewardPath.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 1853, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Day of Judgment", 1858, Rarity.RARE, mage.cards.d.DayOfJudgment.class));
+ cards.add(new SetCardInfo("Temporal Extortion", 1859, Rarity.RARE, mage.cards.t.TemporalExtortion.class));
+ cards.add(new SetCardInfo("Toxic Deluge", 1860, Rarity.RARE, mage.cards.t.ToxicDeluge.class));
+ cards.add(new SetCardInfo("Praetor's Grasp", 1861, Rarity.RARE, mage.cards.p.PraetorsGrasp.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Star of Extinction", 1862, Rarity.RARE, mage.cards.s.StarOfExtinction.class));
+ cards.add(new SetCardInfo("Staff of the Storyteller", 1863, Rarity.RARE, mage.cards.s.StaffOfTheStoryteller.class));
+ cards.add(new SetCardInfo("Blade of Selves", 1864, Rarity.RARE, mage.cards.b.BladeOfSelves.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Umezawa's Jitte", 1865, Rarity.RARE, mage.cards.u.UmezawasJitte.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Colossus Hammer", 1866, Rarity.RARE, mage.cards.c.ColossusHammer.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Sword of Truth and Justice", 1867, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Prismatic Ending", 1868, Rarity.RARE, mage.cards.p.PrismaticEnding.class));
+ cards.add(new SetCardInfo("Cyclonic Rift", 1869, Rarity.RARE, mage.cards.c.CyclonicRift.class));
+ 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));
@@ -1851,7 +1874,25 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Benevolent Hydra", 1889, Rarity.RARE, mage.cards.b.BenevolentHydra.class));
cards.add(new SetCardInfo("Forgotten Ancient", 1890, Rarity.RARE, mage.cards.f.ForgottenAncient.class));
cards.add(new SetCardInfo("Animar, Soul of Elements", 1891, Rarity.MYTHIC, mage.cards.a.AnimarSoulOfElements.class));
+ cards.add(new SetCardInfo("Secret Rendezvous", 1892, Rarity.RARE, mage.cards.s.SecretRendezvous.class));
+ cards.add(new SetCardInfo("Serenity", 1893, Rarity.RARE, mage.cards.s.Serenity.class));
cards.add(new SetCardInfo("Esika's Chariot", 1894, Rarity.RARE, mage.cards.e.EsikasChariot.class));
+ cards.add(new SetCardInfo("Realms Uncharted", 1895, Rarity.RARE, mage.cards.r.RealmsUncharted.class));
+ cards.add(new SetCardInfo("Morophon, the Boundless", 1896, Rarity.MYTHIC, mage.cards.m.MorophonTheBoundless.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Raise the Palisade", 1897, Rarity.RARE, mage.cards.r.RaiseThePalisade.class));
+ cards.add(new SetCardInfo("Bitterblossom", 1898, Rarity.MYTHIC, mage.cards.b.Bitterblossom.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Taurean Mauler", 1899, Rarity.RARE, mage.cards.t.TaureanMauler.class));
+ cards.add(new SetCardInfo("Avenger of Zendikar", 1900, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Kindred Summons", 1901, Rarity.RARE, mage.cards.k.KindredSummons.class));
+ cards.add(new SetCardInfo("Tendershoot Dryad", 1902, Rarity.RARE, mage.cards.t.TendershootDryad.class));
+ cards.add(new SetCardInfo("Coat of Arms", 1903, Rarity.RARE, mage.cards.c.CoatOfArms.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Maskwood Nexus", 1904, Rarity.RARE, mage.cards.m.MaskwoodNexus.class));
+ cards.add(new SetCardInfo("Sol Ring", 1905, Rarity.RARE, mage.cards.s.SolRing.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Shapeshifter", 1906, Rarity.RARE, mage.cards.s.Shapeshifter.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Shapeshifter", 1907, Rarity.RARE, mage.cards.s.Shapeshifter.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Shapeshifter", 1908, Rarity.RARE, mage.cards.s.Shapeshifter.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Shapeshifter", 1909, Rarity.RARE, mage.cards.s.Shapeshifter.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Rin and Seri, Inseparable", 1910, Rarity.MYTHIC, mage.cards.r.RinAndSeriInseparable.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Karmic Guide", 1911, Rarity.RARE, mage.cards.k.KarmicGuide.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ninja of the Deep Hours", 1912, Rarity.RARE, mage.cards.n.NinjaOfTheDeepHours.class));
cards.add(new SetCardInfo("Captain Sisay", 1913, Rarity.MYTHIC, mage.cards.c.CaptainSisay.class, NON_FULL_USE_VARIOUS));
@@ -1884,11 +1925,16 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Swamp", 1941, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mountain", 1942, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forest", 1943, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
+ cards.add(new SetCardInfo("Morophon, the Boundless", 1944, Rarity.MYTHIC, mage.cards.m.MorophonTheBoundless.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Big Score", 1955, Rarity.RARE, mage.cards.b.BigScore.class));
cards.add(new SetCardInfo("Final Fortune", 1956, Rarity.RARE, mage.cards.f.FinalFortune.class));
cards.add(new SetCardInfo("Heat Shimmer", 1957, Rarity.RARE, mage.cards.h.HeatShimmer.class));
cards.add(new SetCardInfo("Roiling Vortex", 1958, Rarity.RARE, mage.cards.r.RoilingVortex.class));
cards.add(new SetCardInfo("Wheel of Misfortune", 1959, Rarity.RARE, mage.cards.w.WheelOfMisfortune.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Marwyn, the Nurturer", 1960, Rarity.RARE, mage.cards.m.MarwynTheNurturer.class));
+ 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));
@@ -1911,21 +1957,81 @@ public class SecretLairDrop extends ExpansionSet {
cards.add(new SetCardInfo("Dragonlord Ojutai", "1973b", Rarity.MYTHIC, mage.cards.d.DragonlordOjutai.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragonlord Silumgar", 1974, Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragonlord Silumgar", "1974b", Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Deadly Dispute", 1980, Rarity.RARE, mage.cards.d.DeadlyDispute.class));
+ cards.add(new SetCardInfo("Murderous Rider", 1981, Rarity.RARE, mage.cards.m.MurderousRider.class));
+ cards.add(new SetCardInfo("Zulaport Cutthroat", 1982, Rarity.RARE, mage.cards.z.ZulaportCutthroat.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Aggravated Assault", 1983, Rarity.RARE, mage.cards.a.AggravatedAssault.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Desperate Ritual", 1984, Rarity.RARE, mage.cards.d.DesperateRitual.class));
+ cards.add(new SetCardInfo("Agent of Treachery", 2005, Rarity.RARE, mage.cards.a.AgentOfTreachery.class));
+ cards.add(new SetCardInfo("Priest of Forgotten Gods", 2006, Rarity.RARE, mage.cards.p.PriestOfForgottenGods.class));
+ 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("Goblin Bombardment", 2024, Rarity.RARE, mage.cards.g.GoblinBombardment.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Orcish Lumberjack", 2025, Rarity.RARE, mage.cards.o.OrcishLumberjack.class));
+ cards.add(new SetCardInfo("Constant Mists", 2026, Rarity.RARE, mage.cards.c.ConstantMists.class));
+ cards.add(new SetCardInfo("Song of the Dryads", 2027, Rarity.RARE, mage.cards.s.SongOfTheDryads.class));
+ cards.add(new SetCardInfo("Consecrated Sphinx", 2028, Rarity.MYTHIC, mage.cards.c.ConsecratedSphinx.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Resculpt", 2029, Rarity.RARE, mage.cards.r.Resculpt.class));
+ cards.add(new SetCardInfo("Mirage Mirror", 2030, Rarity.RARE, mage.cards.m.MirageMirror.class));
+ cards.add(new SetCardInfo("Scion of Draco", 2031, Rarity.MYTHIC, mage.cards.s.ScionOfDraco.class));
+ cards.add(new SetCardInfo("Lava Dart", 2037, Rarity.RARE, mage.cards.l.LavaDart.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Monastery Swiftspear", 2038, Rarity.RARE, mage.cards.m.MonasterySwiftspear.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Soul-Scar Mage", 2039, Rarity.RARE, mage.cards.s.SoulScarMage.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Underworld Breach", 2040, Rarity.RARE, mage.cards.u.UnderworldBreach.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Mishra's Bauble", 2041, Rarity.RARE, mage.cards.m.MishrasBauble.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Lava Dart", 2042, Rarity.RARE, mage.cards.l.LavaDart.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Monastery Swiftspear", 2043, Rarity.RARE, mage.cards.m.MonasterySwiftspear.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Soul-Scar Mage", 2044, Rarity.RARE, mage.cards.s.SoulScarMage.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Underworld Breach", 2045, Rarity.RARE, mage.cards.u.UnderworldBreach.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Mishra's Bauble", 2046, Rarity.RARE, mage.cards.m.MishrasBauble.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Chain Lightning", 2047, Rarity.RARE, mage.cards.c.ChainLightning.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Dragon's Rage Channeler", 2048, Rarity.RARE, mage.cards.d.DragonsRageChanneler.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Lava Spike", 2049, Rarity.RARE, mage.cards.l.LavaSpike.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Rift Bolt", 2050, Rarity.RARE, mage.cards.r.RiftBolt.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Skewer the Critics", 2051, Rarity.RARE, mage.cards.s.SkewerTheCritics.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Chain Lightning", 2052, Rarity.RARE, mage.cards.c.ChainLightning.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Dragon's Rage Channeler", 2053, Rarity.RARE, mage.cards.d.DragonsRageChanneler.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Lava Spike", 2054, Rarity.RARE, mage.cards.l.LavaSpike.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Rift Bolt", 2055, Rarity.RARE, mage.cards.r.RiftBolt.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Skewer the Critics", 2056, Rarity.RARE, mage.cards.s.SkewerTheCritics.class, NON_FULL_USE_VARIOUS));
+ 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("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("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));
+ cards.add(new SetCardInfo("Swamp", 2078, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
+ cards.add(new SetCardInfo("Mountain", 2079, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
+ cards.add(new SetCardInfo("Forest", 2080, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
+ cards.add(new SetCardInfo("Feed the Swarm", 7001, Rarity.RARE, mage.cards.f.FeedTheSwarm.class));
+ cards.add(new SetCardInfo("Forge Anew", 7002, Rarity.RARE, mage.cards.f.ForgeAnew.class));
+ cards.add(new SetCardInfo("Silence", 7003, Rarity.RARE, mage.cards.s.Silence.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Smothering Tithe", 7009, Rarity.RARE, mage.cards.s.SmotheringTithe.class));
cards.add(new SetCardInfo("Counterspell", 7010, Rarity.RARE, mage.cards.c.Counterspell.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dismember", 7011, Rarity.RARE, mage.cards.d.Dismember.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Command Tower", 7012, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Minds Aglow", 7028, Rarity.RARE, mage.cards.m.MindsAglow.class));
+ cards.add(new SetCardInfo("Command Tower", 7029, Rarity.RARE, mage.cards.c.CommandTower.class, NON_FULL_USE_VARIOUS));
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("Ruination", 9993, Rarity.RARE, mage.cards.r.Ruination.class));
- cards.add(new SetCardInfo("Mogis, God of Slaughter", 9994, Rarity.RARE, mage.cards.m.MogisGodOfSlaughter.class, NON_FULL_USE_VARIOUS));
+ 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));
cards.add(new SetCardInfo("Rograkh, Son of Rohgahh", 9996, Rarity.RARE, mage.cards.r.RograkhSonOfRohgahh.class));
cards.add(new SetCardInfo("Geralf's Messenger", 9997, Rarity.RARE, mage.cards.g.GeralfsMessenger.class, NON_FULL_USE_VARIOUS));
diff --git a/Mage.Sets/src/mage/sets/SecretLairShowdown.java b/Mage.Sets/src/mage/sets/SecretLairShowdown.java
index 49044f8cb02..2d6802320d5 100644
--- a/Mage.Sets/src/mage/sets/SecretLairShowdown.java
+++ b/Mage.Sets/src/mage/sets/SecretLairShowdown.java
@@ -25,6 +25,7 @@ public class SecretLairShowdown extends ExpansionSet {
cards.add(new SetCardInfo("Dark Ritual", 16, Rarity.RARE, mage.cards.d.DarkRitual.class));
cards.add(new SetCardInfo("Death's Shadow", 8, Rarity.RARE, mage.cards.d.DeathsShadow.class));
cards.add(new SetCardInfo("Dragonlord Silumgar", 9, Rarity.MYTHIC, mage.cards.d.DragonlordSilumgar.class));
+ cards.add(new SetCardInfo("Echo of Death's Wail", 356, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class));
cards.add(new SetCardInfo("Eldritch Evolution", 5, Rarity.RARE, mage.cards.e.EldritchEvolution.class));
cards.add(new SetCardInfo("Explore", 12, Rarity.RARE, mage.cards.e.Explore.class));
cards.add(new SetCardInfo("Expressive Iteration", 13, Rarity.RARE, mage.cards.e.ExpressiveIteration.class));
@@ -35,10 +36,12 @@ public class SecretLairShowdown extends ExpansionSet {
cards.add(new SetCardInfo("Goblin Guide", 23, Rarity.RARE, mage.cards.g.GoblinGuide.class));
cards.add(new SetCardInfo("Island", 32, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Karn Liberated", 36, Rarity.MYTHIC, mage.cards.k.KarnLiberated.class));
+ cards.add(new SetCardInfo("Laughing Jasper Flint", 44, Rarity.RARE, mage.cards.l.LaughingJasperFlint.class));
cards.add(new SetCardInfo("Lightning Bolt", 21, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Bolt", 37, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Living End", 30, Rarity.MYTHIC, mage.cards.l.LivingEnd.class));
cards.add(new SetCardInfo("Mayhem Devil", 28, Rarity.RARE, mage.cards.m.MayhemDevil.class));
+ cards.add(new SetCardInfo("Mountain", 34, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Murktide Regent", 17, Rarity.MYTHIC, mage.cards.m.MurktideRegent.class));
cards.add(new SetCardInfo("Nexus of Fate", 27, Rarity.RARE, mage.cards.n.NexusOfFate.class));
cards.add(new SetCardInfo("Plains", 31, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
@@ -49,14 +52,15 @@ public class SecretLairShowdown extends ExpansionSet {
cards.add(new SetCardInfo("Relentless Rats", 10, Rarity.RARE, mage.cards.r.RelentlessRats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Relentless Rats", 11, Rarity.RARE, mage.cards.r.RelentlessRats.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seasoned Pyromancer", 24, Rarity.MYTHIC, mage.cards.s.SeasonedPyromancer.class));
+ cards.add(new SetCardInfo("Shoot the Sheriff", 43, Rarity.RARE, mage.cards.s.ShootTheSheriff.class));
cards.add(new SetCardInfo("Sleight of Hand", 25, Rarity.RARE, mage.cards.s.SleightOfHand.class));
cards.add(new SetCardInfo("Spell Pierce", 18, Rarity.RARE, mage.cards.s.SpellPierce.class));
cards.add(new SetCardInfo("Springleaf Drum", 22, Rarity.RARE, mage.cards.s.SpringleafDrum.class));
cards.add(new SetCardInfo("Sudden Edict", 39, Rarity.RARE, mage.cards.s.SuddenEdict.class));
cards.add(new SetCardInfo("Supreme Verdict", 26, Rarity.RARE, mage.cards.s.SupremeVerdict.class));
+ cards.add(new SetCardInfo("Swamp", 33, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Swords to Plowshares", 20, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class));
- cards.add(new SetCardInfo("Tribute to Horobi", 356, Rarity.RARE, mage.cards.t.TributeToHorobi.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("Tribute to Horobi", 356, Rarity.RARE, mage.cards.t.TributeToHorobi.class));
cards.add(new SetCardInfo("Ugin, the Spirit Dragon", 6, Rarity.MYTHIC, mage.cards.u.UginTheSpiritDragon.class));
cards.add(new SetCardInfo("Unholy Heat", 4, Rarity.RARE, mage.cards.u.UnholyHeat.class));
cards.add(new SetCardInfo("Valakut, the Molten Pinnacle", 14, Rarity.RARE, mage.cards.v.ValakutTheMoltenPinnacle.class));
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EvokeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EvokeTest.java
index 2797e335221..6190386f55a 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EvokeTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EvokeTest.java
@@ -42,7 +42,7 @@ public class EvokeTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shriekmaw");
setChoice(playerA, "Cast with Evoke alternative cost: {1}{B} (source: Shriekmaw");
- setChoice(playerA, "When this permanent enters the battlefield, if its evoke cost was paid, its controller sacrifices it."); // stack triggers
+ setChoice(playerA, "When this permanent enters, if its evoke cost was paid, its controller sacrifices it."); // stack triggers
addTarget(playerA, "Silvercoat Lion"); // choice for Shriekmaw Destroy trigger
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Exhume");
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java
index 25d12b4ea0e..0218ceb7a94 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java
@@ -1,5 +1,8 @@
package org.mage.test.cards.enchantments;
+import mage.abilities.common.SagaAbility;
+import mage.abilities.mana.ColorlessManaAbility;
+import mage.abilities.mana.RedManaAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
@@ -148,8 +151,10 @@ public class SagaTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_TURN);
execute();
- assertPermanentCount(playerA, saga, 0);
- assertGraveyardCount(playerA, saga, 1);
+ assertGraveyardCount(playerA, saga, 0);
+ assertAbilityCount(playerA, saga, ColorlessManaAbility.class, 1);
+ assertAbilityCount(playerA, saga, RedManaAbility.class, 1);
+ assertAbilityCount(playerA, saga, SagaAbility.class, 0);
assertPermanentCount(playerA, moon, 1);
}
@@ -171,8 +176,11 @@ public class SagaTest extends CardTestPlayerBase {
setStopAt(1, PhaseStep.END_TURN);
execute();
- assertPermanentCount(playerA, saga, 0);
- assertGraveyardCount(playerA, saga, 1);
+ assertGraveyardCount(playerA, saga, 0);
+ // TODO: This should be 0 but the ability still triggers due to blood moon issues
+ // assertAbilityCount(playerA, saga, ColorlessManaAbility.class, 0);
+ assertAbilityCount(playerA, saga, RedManaAbility.class, 1);
+ assertAbilityCount(playerA, saga, SagaAbility.class, 0);
assertPermanentCount(playerA, moon, 1);
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/bbd/ComboAttackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/bbd/ComboAttackTest.java
new file mode 100644
index 00000000000..2acc03e2f9c
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/bbd/ComboAttackTest.java
@@ -0,0 +1,86 @@
+package org.mage.test.cards.single.bbd;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author xenohedron
+ */
+public class ComboAttackTest extends CardTestPlayerBase {
+
+ /**
+ * {@link mage.cards.c.ComboAttack Combo Attack} {2}{G}
+ * Sorcery
+ * Two target creatures your team controls each deal damage equal to their power to target creature
+ */
+ private static final String combo = "Combo Attack";
+
+ @Test
+ public void test_Normal() {
+ addCard(Zone.HAND, playerA, combo, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Runeclaw Bear", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Fortress Crab", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, combo, "Memnite^Runeclaw Bear^Fortress Crab");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertGraveyardCount(playerA, combo, 1);
+ assertDamageReceived(playerB, "Fortress Crab", 3);
+
+ }
+
+ @Test
+ public void test_IllegalFirst() {
+ addCard(Zone.HAND, playerA, combo, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Runeclaw Bear", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Fortress Crab", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
+ addCard(Zone.HAND, playerB, "Unsummon");
+ addCard(Zone.BATTLEFIELD, playerB, "Island");
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, combo, "Memnite^Runeclaw Bear^Fortress Crab");
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Unsummon", "Memnite", combo);
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertGraveyardCount(playerA, combo, 1);
+ assertGraveyardCount(playerB, "Unsummon", 1);
+ assertHandCount(playerA, "Memnite", 1);
+ assertDamageReceived(playerB, "Fortress Crab", 2);
+
+ }
+
+ @Test
+ public void test_IllegalSecond() {
+ addCard(Zone.HAND, playerA, combo, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Runeclaw Bear", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Fortress Crab", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
+ addCard(Zone.HAND, playerB, "Unsummon");
+ addCard(Zone.BATTLEFIELD, playerB, "Island");
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, combo, "Memnite^Runeclaw Bear^Fortress Crab");
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Unsummon", "Runeclaw Bear", combo);
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertGraveyardCount(playerA, combo, 1);
+ assertGraveyardCount(playerB, "Unsummon", 1);
+ assertHandCount(playerA, "Runeclaw Bear", 1);
+ assertDamageReceived(playerB, "Fortress Crab", 1);
+
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/blc/RapidAugmenterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/blc/RapidAugmenterTest.java
index 14a755f7eb0..d692e7c7e6f 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/blc/RapidAugmenterTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/blc/RapidAugmenterTest.java
@@ -4,14 +4,9 @@ import mage.abilities.keyword.HasteAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
-import mage.game.permanent.Permanent;
-import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
-import static junit.framework.TestCase.assertEquals;
-import static org.junit.Assert.fail;
-
/**
* @author Susucr
*/
@@ -131,7 +126,7 @@ public class RapidAugmenterTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ephemerate", true);
addTarget(playerA, "Memnite");
- setChoice(playerA, "Whenever another creature you control you control enters"); // order triggers (doesnt matter the order but a choice must be made)
+ setChoice(playerA, "Whenever another creature you control enters"); // order triggers (doesnt matter the order but a choice must be made)
attack(1, playerA, rapidAugmenter, playerB);
// Rapid Augmenter can't be blocked, Alpine Watchdog wont take damage
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmu/SerraParagonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmu/SerraParagonTest.java
index edaa9049494..2e830e4beb0 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dmu/SerraParagonTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dmu/SerraParagonTest.java
@@ -130,7 +130,7 @@ public class SerraParagonTest extends CardTestPlayerBase {
public void testAetherworksMarvel() {
setStrictChooseMode(true);
- // Whenever a permanent you control is put into a graveyard from the battlefield, you get {E}
+ // Whenever a permanent you control is put into a graveyard, you get {E}
addCard(Zone.BATTLEFIELD, playerA, "Aetherworks Marvel");
addCard(Zone.BATTLEFIELD, playerA, paragon);
addCard(Zone.GRAVEYARD, playerA, "Chromatic Star");
@@ -140,7 +140,7 @@ public class SerraParagonTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chromatic Star", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Creeping Corrosion", true);
setChoice(playerA, "When this permanent is put into a graveyard from the battlefield, exile it and you gain 2 life."); // stack triggers
- setChoice(playerA, "Whenever a permanent you control is put into a graveyard from the battlefield, you get {E}", 2); // stack triggers
+ setChoice(playerA, "Whenever a permanent you control is put into a graveyard, you get {E}", 2); // stack triggers
// Last trigger is: "When {this} is put into a graveyard from the battlefield, draw a card." from Chromatic Star
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
runCode("energy counter is 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkEnergyCount(info, player, 2));
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java
new file mode 100644
index 00000000000..7330cb5246e
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fic/LifestreamsBlessingTest.java
@@ -0,0 +1,92 @@
+package org.mage.test.cards.single.fic;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author TheElk801
+ */
+public class LifestreamsBlessingTest extends CardTestPlayerBase {
+
+ private static final String blessing = "Lifestream's Blessing";
+ private static final String jackal = "Trained Jackal";
+ private static final String bear = "Ashcoat Bear";
+ private static final String giant = "Hill Giant";
+
+ @Test
+ public void testRegular() {
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
+ addCard(Zone.BATTLEFIELD, playerA, jackal);
+ addCard(Zone.BATTLEFIELD, playerB, giant);
+ addCard(Zone.HAND, playerA, blessing);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing);
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertHandCount(playerA, 1);
+ assertLife(playerA, 20);
+ }
+
+ @Test
+ public void testFlashIn22() {
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 6 + 2);
+ addCard(Zone.BATTLEFIELD, playerA, jackal);
+ addCard(Zone.BATTLEFIELD, playerB, giant);
+ addCard(Zone.HAND, playerA, blessing);
+ addCard(Zone.HAND, playerA, bear);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing);
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bear);
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertHandCount(playerA, 1);
+ assertLife(playerA, 20);
+ }
+
+ private static final String twincast = "Twincast";
+
+ @Test
+ public void testTwincast() {
+ addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6 + 2);
+ addCard(Zone.BATTLEFIELD, playerA, jackal);
+ addCard(Zone.BATTLEFIELD, playerB, giant);
+ addCard(Zone.HAND, playerA, blessing);
+ addCard(Zone.HAND, playerA, twincast);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, blessing);
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, twincast, blessing);
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertHandCount(playerA, 1);
+ assertLife(playerA, 20);
+ }
+
+ @Test
+ public void testForetell() {
+ addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
+ addCard(Zone.BATTLEFIELD, playerA, jackal);
+ addCard(Zone.BATTLEFIELD, playerB, giant);
+ addCard(Zone.HAND, playerA, blessing);
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "For");
+ activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "For");
+
+ setStrictChooseMode(true);
+ setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertHandCount(playerA, 1 + 1);
+ assertLife(playerA, 20 + 2);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fin/ZackFairTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fin/ZackFairTest.java
new file mode 100644
index 00000000000..842b7a213f8
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fin/ZackFairTest.java
@@ -0,0 +1,110 @@
+package org.mage.test.cards.single.fin;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import mage.counters.CounterType;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author Susucr
+ */
+public class ZackFairTest extends CardTestPlayerBase {
+
+ /**
+ * {@link mage.cards.z.ZackFair Zack Fair} {W}
+ * Legendary Creature — Human Soldier
+ * Zack Fair enters with a +1/+1 counter on it.
+ * {1}, Sacrifice Zack Fair: Target creature you control gains indestructible until end of turn. Put Zack Fair’s counters on that creature and attach an Equipment that was attached to Zack Fair to that creature.
+ * 0/1
+ */
+ private static final String zack = "Zack Fair";
+
+ @Test
+ public void test_NoEquip() {
+ addCard(Zone.HAND, playerA, zack, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Squire");
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, zack, true);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}", "Squire");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertCounterCount(playerA, "Squire", CounterType.P1P1, 1);
+ }
+
+ @Test
+ public void test_OtherCountersToo() {
+ addCard(Zone.HAND, playerA, zack, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Squire");
+ /**
+ * Lifelink
+ * Cycling {1}{W} ({1}{W}, Discard this card: Draw a card.)
+ * When you cycle this card, put a lifelink counter on target creature you control.
+ */
+ addCard(Zone.HAND, playerA, "Splendor Mare");
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, zack, true);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling ");
+ addTarget(playerA, zack);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}", "Squire");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertCounterCount(playerA, "Squire", CounterType.P1P1, 1);
+ assertCounterCount(playerA, "Squire", CounterType.LIFELINK, 1);
+ }
+
+ @Test
+ public void test_OneEquip() {
+ addCard(Zone.HAND, playerA, zack, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Squire");
+ addCard(Zone.BATTLEFIELD, playerA, "Short Sword");
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, zack, true);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {1}", zack);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Sacrifice", "Squire");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertCounterCount(playerA, "Squire", CounterType.P1P1, 1);
+ assertAttachedTo(playerA, "Short Sword", "Squire", true);
+ }
+
+ @Test
+ public void test_TwoEquip() {
+ addCard(Zone.HAND, playerA, zack, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Squire");
+ addCard(Zone.BATTLEFIELD, playerA, "Short Sword");
+ addCard(Zone.BATTLEFIELD, playerA, "Golem-Skin Gauntlets");
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, zack, true);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {1}", zack);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {2}", zack);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Sacrifice", "Squire");
+
+ setChoice(playerA, "Short Sword");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertCounterCount(playerA, "Squire", CounterType.P1P1, 1);
+ assertAttachedTo(playerA, "Short Sword", "Squire", true);
+ assertAttachedTo(playerA, "Golem-Skin Gauntlets", "Squire", false);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/MulldrifterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/MulldrifterTest.java
index f8590a7dc9a..2c48a315486 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/MulldrifterTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lrw/MulldrifterTest.java
@@ -51,7 +51,7 @@ public class MulldrifterTest extends CardTestPlayerBase {
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mulldrifter");
setChoice(playerA, "Cast with Evoke alternative cost: {2}{U} (source: Mulldrifter");
setStopAt(1, PhaseStep.BEGIN_COMBAT);
- setChoice(playerA, "When this permanent enters the battlefield, if its evoke cost was paid, its controller sacrifices it"); // stack triggers
+ setChoice(playerA, "When this permanent enters, if its evoke cost was paid, its controller sacrifices it"); // stack triggers
execute();
@@ -67,7 +67,7 @@ public class MulldrifterTest extends CardTestPlayerBase {
public void testMulldrifterFlickered() {
setStrictChooseMode(true);
- // {4}{U} When Mulldrifter enters the battlefield, draw two cards. Evoke {2}{U}
+ // {4}{U} When Mulldrifter enters, draw two cards. Evoke {2}{U}
addCard(Zone.BATTLEFIELD, playerA, "Mulldrifter"); // 2/2
addCard(Zone.BATTLEFIELD, playerA, "Merfolk Looter"); // 1/1
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
@@ -86,4 +86,4 @@ public class MulldrifterTest extends CardTestPlayerBase {
assertGraveyardCount(playerA, "Ghostly Flicker", 1);
assertHandCount(playerA, 2); // should have drawn 2 cards
}
-}
\ No newline at end of file
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/PheliaExuberantShepherdTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/PheliaExuberantShepherdTest.java
index 1abb61f00cf..64b36e9b337 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/PheliaExuberantShepherdTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/PheliaExuberantShepherdTest.java
@@ -149,4 +149,35 @@ public class PheliaExuberantShepherdTest extends CardTestPlayerBase {
assertPermanentCount(playerA, "Memnite", 1);
}
+ // bug: return trigger should not return cards exiled the turn before and not
+ // returned due to a Stifle effect
+ @Test
+ public void test_Stifle() {
+ setStrictChooseMode(true);
+
+ addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1);
+ addCard(Zone.HAND, playerB, "Stifle", 1);
+ addCard(Zone.BATTLEFIELD, playerB, "Island", 1);
+
+ attack(1, playerA, phelia, playerB);
+ addTarget(playerA, "Memnite");
+
+ castSpell(1, PhaseStep.END_TURN, playerB, "Stifle", "stack ability (At the beginning");
+
+ checkExileCount("Memnite still exiled", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
+
+ attack(3, playerA, phelia, playerB);
+ addTarget(playerA, "Ornithopter");
+
+ // end of turn trigger: Ornithopter returns.
+
+ setStopAt(4, PhaseStep.UPKEEP);
+ execute();
+
+ assertPowerToughness(playerA, phelia, 2 + 1, 2 + 1);
+ assertExileCount(playerA, "Memnite", 1);
+ assertPermanentCount(playerA, "Ornithopter", 1);
+ }
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/OminousRoostTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/OminousRoostTest.java
index 447c0e8d246..b0bc901ec55 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/OminousRoostTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/OminousRoostTest.java
@@ -15,48 +15,48 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
* @author alexander-novo, Alex-Vasile
*/
public class OminousRoostTest extends CardTestPlayerBase {
- private static final String ominousRoost = "Ominous Roost";
+ private static final String ominousRoost = "Ominous Roost";
- /**
- * Reported bug: https://github.com/magefree/mage/issues/9078
- * If Ominous Roost is in your library, it will trigger any time you cast a spell from your graveyard.
- */
- @Test
- public void doesNotTriggerFromOtherZones() {
- addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
+ /**
+ * Reported bug: https://github.com/magefree/mage/issues/9078
+ * If Ominous Roost is in your library, it will trigger any time you cast a spell from your graveyard.
+ */
+ @Test
+ public void doesNotTriggerFromOtherZones() {
+ addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
- addCard(Zone.EXILED, playerA, ominousRoost);
- addCard(Zone.LIBRARY, playerA, ominousRoost);
- addCard(Zone.GRAVEYARD, playerA, ominousRoost);
- addCard(Zone.HAND, playerA, ominousRoost);
+ addCard(Zone.EXILED, playerA, ominousRoost);
+ addCard(Zone.LIBRARY, playerA, ominousRoost);
+ addCard(Zone.GRAVEYARD, playerA, ominousRoost);
+ addCard(Zone.HAND, playerA, ominousRoost);
- // Flashback {2}{R}
- // Create a treasure token
- addCard(Zone.GRAVEYARD, playerA, "Strike It Rich");
+ // Flashback {2}{R}
+ // Create a treasure token
+ addCard(Zone.GRAVEYARD, playerA, "Strike It Rich");
- setStrictChooseMode(true);
+ setStrictChooseMode(true);
- activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback {2}{R}");
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback {2}{R}");
- setStopAt(1, PhaseStep.END_TURN);
- execute();
- assertPermanentCount(playerA, ominousRoost, 0);
- assertPermanentCount(playerA, "Bird Token", 0); // None of the cards are on the field, so it should not have triggered
- }
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+ assertPermanentCount(playerA, ominousRoost, 0);
+ assertPermanentCount(playerA, "Bird Token", 0); // None of the cards are on the field, so it should not have triggered
+ }
- /**
- * Test that it triggers on ETB
- */
- @Test
- public void triggersOnOwnETB() {
- addCard(Zone.HAND, playerA, ominousRoost);
- addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
+ /**
+ * Test that it triggers on ETB
+ */
+ @Test
+ public void triggersOnOwnETB() {
+ addCard(Zone.HAND, playerA, ominousRoost);
+ addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
- castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ominousRoost);
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ominousRoost);
- setStopAt(1, PhaseStep.END_TURN);
- execute();
- assertPermanentCount(playerA, ominousRoost, 1);
- assertPermanentCount(playerA, "Bird Token", 1);
- }
+ setStopAt(1, PhaseStep.END_TURN);
+ execute();
+ assertPermanentCount(playerA, ominousRoost, 1);
+ assertPermanentCount(playerA, "Bird Token", 1);
+ }
}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/SigardasSplendorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/SigardasSplendorTest.java
new file mode 100644
index 00000000000..95b7f30edda
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mid/SigardasSplendorTest.java
@@ -0,0 +1,76 @@
+package org.mage.test.cards.single.mid;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * {@link mage.cards.s.SigardasSplendor Sigarda's Splendor}
+ * {2}{W}{W}
+ * Enchantment
+ * As Sigarda’s Splendor enters the battlefield, note your life total.
+ * At the beginning of your upkeep, draw a card if your life total is greater than or equal
+ * to the last noted life total for Sigarda’s Splendor. Then note your life total.
+ * Whenever you cast a white spell, you gain 1 life.
+ *
+ * @author notgreat
+ */
+public class SigardasSplendorTest extends CardTestPlayerBase {
+ private static final String sigardasSplendor = "Sigarda's Splendor";
+
+ //Original bug: [BUG] Sigarda's Splendor always draws you a card the turn after it came into play #9872
+ //Test added while changing abilities' zcc while entering the battlefield
+
+ @Test
+ public void sigardasSplendorTestBasic() {
+ addCard(Zone.HAND, playerA, sigardasSplendor, 2);
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
+
+ setStrictChooseMode(true);
+
+ checkHandCount("Initial hand size", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, sigardasSplendor);
+ checkHandCount("Initial hand size (2)", 1, PhaseStep.END_TURN, playerA, 1); //-1 sigarda
+ checkLife("Initial life", 1, PhaseStep.END_TURN, playerA, 20);
+ checkHandCount("Did not draw on 1st upkeep", 3, PhaseStep.PRECOMBAT_MAIN, playerA, 3); //-1 sigarda, +1 natural draw, +1 trigger
+ castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, sigardasSplendor);
+ checkHandCount("Did not draw on 1st upkeep (2)", 3, PhaseStep.END_TURN, playerA, 2); //-2 sigarda, +1 natural draw, +1 trigger
+ checkLife("Initial life", 3, PhaseStep.END_TURN, playerA, 21);
+
+ setChoice(playerA, "At the beginning of your upkeep"); //stack triggers
+ setStopAt(5, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+ assertPermanentCount(playerA, sigardasSplendor, 2);
+ assertHandCount(playerA, 5); //-2 sigardas, +2 natural draw, +3 trigger
+ }
+
+ @Test
+ public void sigardasSplendorTestDamaged() {
+ addCard(Zone.HAND, playerA, sigardasSplendor, 2);
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
+
+ addCard(Zone.HAND, playerB, "Scorching Spear", 2);
+ addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
+ setStrictChooseMode(true);
+
+ checkHandCount("Initial hand size", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
+ castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, sigardasSplendor);
+ checkHandCount("Initial hand size (2)", 1, PhaseStep.END_TURN, playerA, 1); //-1 sigarda
+ checkLife("Initial life", 1, PhaseStep.END_TURN, playerA, 20);
+ castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Scorching Spear", playerA);
+ checkLife("Post-spear 1", 2, PhaseStep.END_TURN, playerA, 19);
+ checkHandCount("Did not draw on 1st upkeep", 3, PhaseStep.PRECOMBAT_MAIN, playerA, 2); //-1 sigarda, +1 natural draw
+ castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, sigardasSplendor);
+ checkHandCount("Did not draw on 1st upkeep (2)", 3, PhaseStep.END_TURN, playerA, 1); //-2 sigarda, +1 natural draw
+ checkLife("Post-splendors", 3, PhaseStep.END_TURN, playerA, 20);
+ castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Scorching Spear", playerA);
+ checkLife("Post-spear 2", 4, PhaseStep.END_TURN, playerA, 19);
+
+ setChoice(playerA, "At the beginning of your upkeep"); //stack triggers
+ setStopAt(5, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+ assertPermanentCount(playerA, sigardasSplendor, 2);
+ assertHandCount(playerA, 3); //-2 sigardas, +2 natural draw, +1 trigger
+ }
+}
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 43cc503eb68..16b0a3f9ae9 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
@@ -97,10 +97,11 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase {
addTarget(playerA, "Memnite");
addTarget(playerA, "Ornithopter");
+ // turn 2
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Sacrifice");
addTarget(playerB, vault);
- //Turn 3
+ // turn 3
addTarget(playerA, "Squire");
addTarget(playerA, "Watchwolf");
@@ -113,10 +114,10 @@ public class Vault13DwellersJourneyTest extends CardTestPlayerBase {
addTarget(playerA, "Mountain"); // for Scry 2
// turn 7
- checkExileCount("before III: Memnite exiled", 5, PhaseStep.UPKEEP, playerB, "Memnite", 1);
- checkExileCount("before III: Ornithopter exiled", 5, PhaseStep.UPKEEP, playerB, "Ornithopter", 1);
- checkExileCount("before III: Squire exiled", 5, PhaseStep.UPKEEP, playerB, "Squire", 1);
- checkExileCount("before III: Watchwolf exiled", 5, PhaseStep.UPKEEP, playerB, "Watchwolf", 1);
+ checkExileCount("before III: Memnite exiled", 7, PhaseStep.UPKEEP, playerB, "Memnite", 1);
+ checkExileCount("before III: Ornithopter exiled", 7, PhaseStep.UPKEEP, playerB, "Ornithopter", 1);
+ checkExileCount("before III: Squire exiled", 7, PhaseStep.UPKEEP, playerB, "Squire", 1);
+ checkExileCount("before III: Watchwolf exiled", 7, PhaseStep.UPKEEP, playerB, "Watchwolf", 1);
setChoice(playerA, "Memnite^Ornithopter");
setStrictChooseMode(true);
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/rna/FontOfAgoniesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/rna/FontOfAgoniesTest.java
new file mode 100644
index 00000000000..d0ae259645d
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/rna/FontOfAgoniesTest.java
@@ -0,0 +1,53 @@
+package org.mage.test.cards.single.rna;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import mage.counters.CounterType;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author Susucr
+ */
+public class FontOfAgoniesTest extends CardTestPlayerBase {
+
+ /**
+ * {@link mage.cards.f.FontOfAgonies Font of Agonies} {B}
+ * Enchantment
+ * Whenever you pay life, put that many blood counters on this enchantment.
+ * {1}{B}, Remove four blood counters from this enchantment: Destroy target creature.
+ */
+ private static final String font = "Font of Agonies";
+
+ @Test
+ public void test_Fetchland() {
+ addCard(Zone.BATTLEFIELD, playerA, font, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Arid Mesa", 1);
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}");
+ addTarget(playerA, "Mountain");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertLife(playerA, 20 - 1);
+ assertCounterCount(playerA, font, CounterType.BLOOD, 1);
+ }
+
+ @Test
+ public void test_Pay2() {
+ addCard(Zone.BATTLEFIELD, playerA, font, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Book of Rass", 1); // {2}, Pay 2 life: Draw a card.
+ addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertLife(playerA, 20 - 2);
+ assertCounterCount(playerA, font, CounterType.BLOOD, 2);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/stx/SpitefulSquadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/stx/SpitefulSquadTest.java
new file mode 100644
index 00000000000..a9cb149f535
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/stx/SpitefulSquadTest.java
@@ -0,0 +1,40 @@
+package org.mage.test.cards.single.stx;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import mage.counters.CounterType;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author Susucr
+ */
+public class SpitefulSquadTest extends CardTestPlayerBase {
+
+ /**
+ * {@link mage.cards.s.SpitefulSquad} {2}{W}{B}
+ * Creature — Human Warlock
+ * Deathtouch
+ * This creature enters with two +1/+1 counters on it.
+ * When this creature dies, put its counters on target creature you control.
+ * 0/0
+ */
+ private static final String squad = "Spiteful Squad";
+
+ @Test
+ public void test_Simple() {
+ addCard(Zone.BATTLEFIELD, playerA, squad);
+ addCard(Zone.HAND, playerA, "Murder");
+ addCard(Zone.BATTLEFIELD, playerA, "Squire");
+ addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder", squad, true);
+ addTarget(playerA, "Squire");
+
+ setStrictChooseMode(true);
+ setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
+ execute();
+
+ assertCounterCount(playerA, "Squire", CounterType.P1P1, 2);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tdc/BetorAncestorsVoiceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tdc/BetorAncestorsVoiceTest.java
new file mode 100644
index 00000000000..ce8df2192bb
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tdc/BetorAncestorsVoiceTest.java
@@ -0,0 +1,45 @@
+package org.mage.test.cards.single.tdc;
+
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import mage.counters.CounterType;
+import org.junit.Test;
+import org.mage.test.player.TestPlayer;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author Susucr
+ */
+public class BetorAncestorsVoiceTest extends CardTestPlayerBase {
+
+ /**
+ * {@link mage.cards.b.BetorAncestorsVoice Betor, Ancestor's Voice} {2}{W}{B}{G}
+ * Legendary Creature — Spirit Dragon
+ * Flying, lifelink
+ * At the beginning of your end step, put a number of +1/+1 counters on up to one other target creature you control equal to the amount of life you gained this turn. Return up to one target creature card with mana value less than or equal to the amount of life you lost this turn from your graveyard to the battlefield.
+ * 3/5
+ */
+ private static final String betor = "Betor, Ancestor's Voice";
+
+ // Bug Report: If you got Betor and Rhox Faithmender on the field, and attack with both.
+ // The gui shows you got the 8 life you are supposed to get, but in the end of turn trigger,
+ // there will be only 4 counters put on a creature.
+ @Test
+ public void test_RhowFaithmender() {
+ addCard(Zone.BATTLEFIELD, playerA, betor, 1);
+ addCard(Zone.BATTLEFIELD, playerA, "Rhox Faithmender", 1);
+
+ attack(1, playerA, betor, playerB);
+ attack(1, playerA, "Rhox Faithmender", playerB);
+
+ addTarget(playerA, "Rhox Faithmender"); // Betor trigger's first target
+ addTarget(playerA, TestPlayer.TARGET_SKIP); // second target
+
+ setStrictChooseMode(true);
+ setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
+ execute();
+
+ assertLife(playerA, 20 + 8);
+ assertCounterCount(playerA, "Rhox Faithmender", CounterType.P1P1, 8);
+ }
+}
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/AshiokWickedManipulatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/AshiokWickedManipulatorTest.java
index d20993bf27b..dc14f0f83a3 100644
--- a/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/AshiokWickedManipulatorTest.java
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/woe/AshiokWickedManipulatorTest.java
@@ -249,8 +249,7 @@ public class AshiokWickedManipulatorTest extends CardTestPlayerBase {
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:");
addTarget(playerA, poet);
// 2 tokens, so stacking trigger.
- setChoice(playerA, "At the beginning of combat on your turn, if a card was put "
- + "into exile this turn, put a +1/+1 counter on this creature.");
+ setChoice(playerA, "At the beginning of combat on your turn,");
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
execute();
@@ -260,8 +259,7 @@ public class AshiokWickedManipulatorTest extends CardTestPlayerBase {
activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:");
addTarget(playerA, lion);
// 2 tokens, so stacking trigger.
- setChoice(playerA, "At the beginning of combat on your turn, if a card was put "
- + "into exile this turn, put a +1/+1 counter on this creature.");
+ setChoice(playerA, "At the beginning of combat on your turn,");
setStopAt(5, PhaseStep.POSTCOMBAT_MAIN);
execute();
@@ -305,4 +303,4 @@ public class AshiokWickedManipulatorTest extends CardTestPlayerBase {
assertExileCount(playerB, 2 + 3 + 3);
}
-}
\ No newline at end of file
+}
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 ed9c0ea463f..e7b9d197590 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
@@ -54,4 +54,32 @@ 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);
+ addCard(Zone.HAND, playerA, flight);
+ addCard(Zone.HAND, playerA, "Flicker of Fate");
+ addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears");
+ addCard(Zone.BATTLEFIELD, playerA, "Memnite");
+
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, flight);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1); //Saga resolves, Bear exile on stack
+ addTarget(playerA, "Grizzly Bears");
+ castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flicker of Fate", flight);
+ addTarget(playerA, "Memnite");
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 2); //Flicker resolves, Memnite exile resolves
+ checkExileCount("Memnite exiled first", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite", 1);
+ checkExileCount("Bear not yet exiled", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 0);
+ waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); //Bear exile resolves
+ checkExileCount("Bear exiled", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1);
+
+ setStrictChooseMode(true);
+ setStopAt(5, PhaseStep.END_TURN);
+ execute();
+
+ assertExileCount(playerA, "Grizzly Bears", 1); //Bear stays exiled
+ assertPermanentCount(playerA, "Memnite", 1);
+ assertGraveyardCount(playerA, flight, 1);
+ }
}
diff --git a/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCard.java b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCard.java
new file mode 100644
index 00000000000..319a3e24ec7
--- /dev/null
+++ b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCard.java
@@ -0,0 +1,13 @@
+package mage.verify.mtgjson;
+
+/**
+ * Commanders Spellbook api: card class
+ *
+ * API docs here
+ *
+ * @author JayDi85
+ */
+public final class SpellBookCard {
+ public int id;
+ public String name;
+}
diff --git a/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCardsPage.java b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCardsPage.java
new file mode 100644
index 00000000000..70ad102054f
--- /dev/null
+++ b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCardsPage.java
@@ -0,0 +1,17 @@
+package mage.verify.mtgjson;
+
+import java.util.List;
+
+/**
+ * Commanders Spellbook api: page class
+ *
+ * API docs here
+ *
+ * @author JayDi85
+ */
+public final class SpellBookCardsPage {
+ public int count;
+ public String next; // can be null on last page
+ public String previous;
+ public List results; // empty on too big page
+}
diff --git a/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCombo.java b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCombo.java
new file mode 100644
index 00000000000..f78a8781542
--- /dev/null
+++ b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookCombo.java
@@ -0,0 +1,17 @@
+package mage.verify.mtgjson;
+
+import java.util.List;
+
+/**
+ * Commanders Spellbook api: full combo
+ *
+ * API docs here
+ *
+ * @author JayDi85
+ */
+public final class SpellBookCombo {
+ public String id; // combo id
+ public List uses; // combo parts
+ public String bracketTag; // can be useful
+ public String description;
+}
diff --git a/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookComboPart.java b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookComboPart.java
new file mode 100644
index 00000000000..8cdaca9429c
--- /dev/null
+++ b/Mage.Verify/src/main/java/mage/verify/mtgjson/SpellBookComboPart.java
@@ -0,0 +1,13 @@
+package mage.verify.mtgjson;
+
+/**
+ * Commanders Spellbook api: combo part (one card info)
+ *
+ * API docs here
+ *
+ * @author JayDi85
+ */
+public final class SpellBookComboPart {
+ public SpellBookCard card;
+ public int quantity;
+}
diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
index 9fb178911de..9c9afcfc5bd 100644
--- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
+++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
@@ -1,6 +1,7 @@
package mage.verify;
import com.google.common.base.CharMatcher;
+import com.google.gson.Gson;
import mage.MageObject;
import mage.Mana;
import mage.ObjectColor;
@@ -30,6 +31,7 @@ import mage.cards.decks.DeckCardLists;
import mage.cards.decks.importer.DeckImporter;
import mage.cards.repository.*;
import mage.choices.Choice;
+import mage.client.remote.XmageURLConnection;
import mage.constants.*;
import mage.filter.Filter;
import mage.filter.predicate.Predicate;
@@ -51,7 +53,9 @@ import mage.utils.SystemUtil;
import mage.verify.mtgjson.MtgJsonCard;
import mage.verify.mtgjson.MtgJsonService;
import mage.verify.mtgjson.MtgJsonSet;
+import mage.verify.mtgjson.SpellBookCardsPage;
import mage.watchers.Watcher;
+import net.java.truevfs.access.TFile;
import org.apache.log4j.Logger;
import org.junit.Assert;
import org.junit.Ignore;
@@ -59,10 +63,14 @@ import org.junit.Test;
import org.mage.plugins.card.dl.sources.ScryfallImageSupportCards;
import org.reflections.Reflections;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.*;
+import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -75,7 +83,7 @@ public class VerifyCardDataTest {
private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class);
- private static final String FULL_ABILITIES_CHECK_SET_CODES = "ODY,TOR,JUD,ONS,LGN,SCG"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all
+ private static final String FULL_ABILITIES_CHECK_SET_CODES = "BLC"; // check ability text due mtgjson, can use multiple sets like MAT;CMD or * for all
private static final boolean CHECK_ONLY_ABILITIES_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages
private static final boolean CHECK_COPYABLE_FIELDS = true; // disable for better verify test performance
@@ -3255,4 +3263,79 @@ public class VerifyCardDataTest {
+ "%29&order=set&as=grid&unique=cards"
);
}
-}
+
+ /**
+ * Helper test to download infinite combos data and prepare it to use in Commander Brackets score system
+ *
+ * How-to use: run it before each main release and upload updated files to github
+ */
+ @Ignore
+ @Test
+ public void downloadAndPrepareCommanderBracketsData() {
+ // download data
+ // load data by pages, max limit = 100, no needs to setup it, ~2000 combos or 20 pages
+ String nextUrl = "https://backend.commanderspellbook.com/variants?format=json&group_by_combo=true&ordering=created&q=cards%3D2+result%3Ainfinite";
+ SpellBookCardsPage page;
+ int pageNumber = 0;
+ List allCombos = new ArrayList<>();
+ while (nextUrl != null && !nextUrl.isEmpty()) {
+ pageNumber++;
+ System.out.println("downloading page " + pageNumber);
+ String res = XmageURLConnection.downloadText(nextUrl);
+ page = new Gson().fromJson(res, SpellBookCardsPage.class);
+ if (page == null || page.results == null) {
+ System.out.println("ERROR, unknown data format: " + res.substring(0, 10) + "...");
+ return;
+ }
+ page.results.forEach(combo -> {
+ if (combo.uses.isEmpty()) {
+ System.out.println("wrong combo uses: " + combo.uses);
+ return;
+ }
+ // Stella Lee, Wild Card - can generate infinite combo by itself, so allow 1 card
+ String card1 = combo.uses.get(0).card.name;
+ String card2 = combo.uses.size() == 1 ? card1 : combo.uses.get(1).card.name;
+ if (card1 != null && card2 != null) {
+ allCombos.add(String.format("%s@%s", card1, card2));
+ }
+ });
+
+ nextUrl = page.next;
+ }
+
+ // save results (run from Mage.Verify)
+ File destFile = new TFile("..\\Mage\\src\\main\\resources\\brackets\\infinite-combos.txt");
+ if (!destFile.exists()) {
+ System.out.println("Can't find dest file " + destFile);
+ return;
+ }
+
+ List infiniteCombosRes;
+ try {
+ infiniteCombosRes = Files.readAllLines(destFile.toPath(), StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ System.out.println("Can't read file " + destFile + " " + e);
+ return;
+ }
+
+ // replace all cards data, but keep comments
+ infiniteCombosRes.removeIf(s -> !s.startsWith("#")
+ || s.startsWith("# Source")
+ || s.startsWith("# Updated")
+ || s.startsWith("# Found")
+ );
+ infiniteCombosRes.add(String.format("# Source: %s", "https://commanderspellbook.com"));
+ infiniteCombosRes.add(String.format("# Updated: %s", LocalDate.now().format(DateTimeFormatter.ISO_DATE)));
+ infiniteCombosRes.add(String.format("# Found: %d", allCombos.size()));
+ infiniteCombosRes.addAll(allCombos); // do not sort, all new combos will be added to the end due spell book default order
+
+ try {
+ Files.write(destFile.toPath(), infiniteCombosRes, StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ System.out.println("Can't write file " + destFile + " " + e);
+ return;
+ }
+
+ System.out.println(String.format("ALL DONE, found and write %d combos", allCombos.size()));
+ }
+}
\ No newline at end of file
diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java
index 2916b50c3ec..a4fc6d9cc7a 100644
--- a/Mage/src/main/java/mage/MageIdentifier.java
+++ b/Mage/src/main/java/mage/MageIdentifier.java
@@ -83,6 +83,7 @@ public enum MageIdentifier {
PrimalPrayersAlternateCast,
QuilledGreatwurmAlternateCast,
WickerfolkIndomitableAlternateCast,
+ UriangerAugureltAlternateCast,
ValgavothTerrorEaterAlternateCast;
/**
diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java
index 4621d104feb..31dee95d241 100644
--- a/Mage/src/main/java/mage/abilities/Ability.java
+++ b/Mage/src/main/java/mage/abilities/Ability.java
@@ -504,6 +504,17 @@ public interface Ability extends Controllable, Serializable {
MageObject getSourceObject(Game game);
void setSourceObjectZoneChangeCounter(int zoneChangeCounter);
+ /**
+ * Initializes the internally stored Source Object ZCC value
+ * to be equal to the source object's current ZCC.
+ *
+ * If the source is an entering permanent, then
+ * the ZCC is set as if the permanent had already entered the battlefield.
+ *
+ * @param game
+ * @param force Update only occurs if stored ZCC is zero or if force is true.
+ */
+ void initSourceObjectZoneChangeCounter(Game game, boolean force);
int getSourceObjectZoneChangeCounter();
diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java
index 65198348e02..ad735b98e74 100644
--- a/Mage/src/main/java/mage/abilities/AbilityImpl.java
+++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java
@@ -272,9 +272,7 @@ public abstract class AbilityImpl implements Ability {
game.applyEffects();
MageObject sourceObject = getSourceObject(game);
- if (getSourceObjectZoneChangeCounter() == 0) {
- setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId()));
- }
+ initSourceObjectZoneChangeCounter(game, false);
setSourcePermanentTransformCount(game);
// if ability can be cast for no mana, clear the mana costs now, because additional mana costs must be paid.
@@ -1664,7 +1662,7 @@ public abstract class AbilityImpl implements Ability {
@Override
public MageObject getSourceObjectIfItStillExists(Game game) {
if (getSourceObjectZoneChangeCounter() == 0
- || getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) {
+ || getSourceObjectZoneChangeCounter() == getCurrentSourceObjectZoneChangeCounter(game)) {
// exists or lki from battlefield
return game.getObject(getSourceId());
}
@@ -1703,6 +1701,27 @@ public abstract class AbilityImpl implements Ability {
this.sourceObjectZoneChangeCounter = sourceObjectZoneChangeCounter;
}
+ @Override
+ public void initSourceObjectZoneChangeCounter(Game game, boolean force) {
+ if (!(this instanceof MageSingleton) && (force || sourceObjectZoneChangeCounter == 0 )) {
+ setSourceObjectZoneChangeCounter(getCurrentSourceObjectZoneChangeCounter(game));
+ }
+ }
+
+ private int getCurrentSourceObjectZoneChangeCounter(Game game){
+ int zcc = game.getState().getZoneChangeCounter(getSourceId());
+ // TODO: Enable this, #13710
+ /*if (game.getPermanentEntering(getSourceId()) != null){
+ // 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
+ zcc += 1;
+ }*/
+ return zcc;
+ }
+
@Override
public int getSourceObjectZoneChangeCounter() {
return sourceObjectZoneChangeCounter;
diff --git a/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java
index a818d19153c..36f5196c1d5 100644
--- a/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java
@@ -1,5 +1,6 @@
package mage.abilities.common;
+import mage.MageItem;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
@@ -23,6 +24,7 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
// retrieve the number of attackers in triggered effects with getValue
public static final String VALUEKEY_NUMBER_ATTACKERS = "number_attackers";
+ public static final String VALUEKEY_NUMBER_DEFENDING_PLAYERS = "number_defending_players";
private final FilterPermanent filter;
private final int minAttackers;
@@ -91,6 +93,17 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
return false;
}
getEffects().setValue(VALUEKEY_NUMBER_ATTACKERS, attackers.size());
+ getEffects().setValue(
+ VALUEKEY_NUMBER_DEFENDING_PLAYERS,
+ attackers.stream()
+ .map(MageItem::getId)
+ .map(game.getCombat()::getDefenderId)
+ .distinct()
+ .map(game::getPlayer)
+ .filter(Objects::nonNull)
+ .mapToInt(x -> 1)
+ .sum()
+ );
if (setTargetPointer) {
getEffects().setTargetPointer(new FixedTargets(new ArrayList<>(attackers), game));
}
diff --git a/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java
index 75e3df42573..0d86a1058c2 100644
--- a/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/DiscardedByOpponentTriggeredAbility.java
@@ -13,13 +13,8 @@ import mage.game.stack.StackObject;
public class DiscardedByOpponentTriggeredAbility extends TriggeredAbilityImpl {
public DiscardedByOpponentTriggeredAbility(Effect effect) {
- this(effect, false);
- }
-
- public DiscardedByOpponentTriggeredAbility(Effect effect, boolean textCardName) {
super(Zone.GRAVEYARD, effect, false);
- setTriggerPhrase("When a spell or ability an opponent controls causes you to discard "
- + (textCardName ? "{this}, " : "this card, "));
+ setTriggerPhrase("When a spell or ability an opponent controls causes you to discard this card");
}
protected DiscardedByOpponentTriggeredAbility(final DiscardedByOpponentTriggeredAbility ability) {
@@ -38,12 +33,10 @@ public class DiscardedByOpponentTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- if (getSourceId().equals(event.getTargetId())) {
- StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
- if (stackObject != null) {
- return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId());
- }
+ if (!getSourceId().equals(event.getTargetId())) {
+ return false;
}
- return false;
+ StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
+ return stackObject != null && game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId());
}
}
diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java
index cc1a5544469..b01369d0766 100644
--- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java
@@ -23,7 +23,11 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
* zone = BATTLEFIELD optional = false
*/
public EntersBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter) {
- this(Zone.BATTLEFIELD, effect, filter, false);
+ this(effect, filter, false);
+ }
+
+ public EntersBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
+ this(Zone.BATTLEFIELD, effect, filter, optional);
}
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional) {
diff --git a/Mage/src/main/java/mage/abilities/common/PlayLandOrCastSpellFromExileTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PlayLandOrCastSpellFromExileTriggeredAbility.java
new file mode 100644
index 00000000000..ff24dcc6cd6
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/common/PlayLandOrCastSpellFromExileTriggeredAbility.java
@@ -0,0 +1,38 @@
+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;
+
+/**
+ * @author TheElk801
+ */
+public class PlayLandOrCastSpellFromExileTriggeredAbility extends TriggeredAbilityImpl {
+
+ public PlayLandOrCastSpellFromExileTriggeredAbility(Effect effect) {
+ super(Zone.BATTLEFIELD, effect);
+ setTriggerPhrase("Whenever you play a land from exile or cast a spell from exile, ");
+ }
+
+ private PlayLandOrCastSpellFromExileTriggeredAbility(final PlayLandOrCastSpellFromExileTriggeredAbility ability) {
+ super(ability);
+ }
+
+ @Override
+ public PlayLandOrCastSpellFromExileTriggeredAbility copy() {
+ return new PlayLandOrCastSpellFromExileTriggeredAbility(this);
+ }
+
+ @Override
+ public boolean checkEventType(GameEvent event, Game game) {
+ return event.getType() == GameEvent.EventType.LAND_PLAYED
+ || event.getType() == GameEvent.EventType.SPELL_CAST;
+ }
+
+ @Override
+ public boolean checkTrigger(GameEvent event, Game game) {
+ return isControlledBy(event.getPlayerId()) && event.getZone() == Zone.EXILED;
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java
index f67a6bdba61..e798718f028 100644
--- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java
@@ -30,8 +30,8 @@ public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbi
this.filter = filter;
this.onlyToControllerGraveyard = onlyToControllerGraveyard;
this.setTargetPointer = setTargetPointer;
- setTriggerPhrase("Whenever " + filter.getMessage() + " is put into " + (onlyToControllerGraveyard ? "your" : "a")
- + " graveyard from the battlefield, ");
+ setTriggerPhrase("Whenever " + filter.getMessage() + " is put into " +
+ (onlyToControllerGraveyard ? "your" : "a") + " graveyard, ");
}
protected PutIntoGraveFromBattlefieldAllTriggeredAbility(final PutIntoGraveFromBattlefieldAllTriggeredAbility ability) {
diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromLibrarySourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromLibrarySourceTriggeredAbility.java
index 22d6e67dd0a..1f61c7b9613 100644
--- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromLibrarySourceTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromLibrarySourceTriggeredAbility.java
@@ -13,7 +13,7 @@ public class PutIntoGraveFromLibrarySourceTriggeredAbility extends ZoneChangeTri
}
public PutIntoGraveFromLibrarySourceTriggeredAbility(Effect effect, boolean optional) {
- super(Zone.LIBRARY, Zone.GRAVEYARD, effect, "When {this} is put into your graveyard from your library, ", optional);
+ super(Zone.LIBRARY, Zone.GRAVEYARD, effect, "When this card is put into your graveyard from your library, ", optional);
}
protected PutIntoGraveFromLibrarySourceTriggeredAbility(final PutIntoGraveFromLibrarySourceTriggeredAbility ability) {
diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlACommanderCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlACommanderCondition.java
index b255fc02f14..44f4579c4ad 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/ControlACommanderCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/ControlACommanderCondition.java
@@ -34,6 +34,6 @@ public enum ControlACommanderCondition implements Condition {
@Override
public String toString() {
- return "If you control a commander";
+ return "you control a commander";
}
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java
deleted file mode 100644
index 92a533b372e..00000000000
--- a/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package mage.abilities.condition.common;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import mage.abilities.Ability;
-import mage.abilities.condition.Condition;
-import mage.filter.FilterPermanent;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
-
-/**
- *
- * @author LevelX2
- */
-public class ControlsPermanentGreatestCMCCondition implements Condition {
-
- private final FilterPermanent filter;
-
- public ControlsPermanentGreatestCMCCondition() {
- this(new FilterPermanent());
- }
-
- public ControlsPermanentGreatestCMCCondition(FilterPermanent filter) {
- super();
- this.filter = filter;
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Set controllers = new HashSet<>();
- Integer maxCMC = null;
-
- List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game);
- for (Permanent permanent : permanents) {
- int cmc = permanent.getManaCost().manaValue();
- if (maxCMC == null || cmc > maxCMC) {
- maxCMC = cmc;
- controllers.clear();
- }
- if (cmc == maxCMC) {
- controllers.add(permanent.getControllerId());
- }
- }
- return controllers.contains(source.getControllerId());
- }
-
- @Override
- public String toString() {
- return "you control the " + filter.getMessage() + " with the highest mana value or tied for the highest mana value";
- }
-
-}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java
index fda6bed36b4..46c9a79e924 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java
@@ -1,5 +1,3 @@
-
-
package mage.abilities.condition.common;
import mage.abilities.Ability;
@@ -9,17 +7,21 @@ import mage.game.Game;
import mage.util.CardUtil;
/**
- * Checks if a the spell was cast with the alternate evoke costs
+ * Checks if a the spell was cast with the alternate evoke costs
*
* @author LevelX2
*/
public enum EvokedCondition implements Condition {
-
instance;
@Override
public boolean apply(Game game, Ability source) {
return CardUtil.checkSourceCostsTagExists(game, source, EvokeAbility.getActivationKey());
}
+
+ @Override
+ public String toString() {
+ return "its evoke cost was paid";
+ }
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/FullPartyCondition.java b/Mage/src/main/java/mage/abilities/condition/common/FullPartyCondition.java
index 885640c2caa..362b89881ce 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/FullPartyCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/FullPartyCondition.java
@@ -8,7 +8,6 @@ import mage.game.Game;
/**
* @author TheElk801
*/
-
public enum FullPartyCondition implements Condition {
instance;
@@ -16,4 +15,9 @@ public enum FullPartyCondition implements Condition {
public boolean apply(Game game, Ability source) {
return PartyCount.instance.calculate(game, source, null) >= 4;
}
+
+ @Override
+ public String toString() {
+ return "you have a full party";
+ }
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/HellbentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/HellbentCondition.java
index cfb80b59616..f94113f2681 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/HellbentCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/HellbentCondition.java
@@ -16,6 +16,6 @@ public enum HellbentCondition implements Condition {
@Override
public String toString() {
- return "if you have no cards in hand";
+ return "you have no cards in hand";
}
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/KickedCostCondition.java b/Mage/src/main/java/mage/abilities/condition/common/KickedCostCondition.java
index b3dcf1ee4d4..3ee36b76a1a 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/KickedCostCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/KickedCostCondition.java
@@ -12,9 +12,9 @@ import mage.game.Game;
*/
public class KickedCostCondition implements Condition {
- protected String kickerCostText;
+ protected final String kickerCostText;
- public KickedCostCondition(String kickerCostText) {
+ public KickedCostCondition(String kickerCostText) {
this.kickerCostText = kickerCostText;
}
@@ -22,4 +22,9 @@ public class KickedCostCondition implements Condition {
public boolean apply(Game game, Ability source) {
return KickerAbility.getKickedCounterStrict(game, source, kickerCostText) > 0;
}
+
+ @Override
+ public String toString() {
+ return "it was kicked with its " + kickerCostText + " kicker";
+ }
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java
index 8c03dd92b39..f2649ac395d 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java
@@ -21,6 +21,6 @@ public enum RaidCondition implements Condition {
@Override
public String toString() {
- return "if you attacked this turn";
+ return "you attacked this turn";
}
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceHasCounterCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceHasCounterCondition.java
index e5d3bf49f5a..c65bf4887d7 100644
--- a/Mage/src/main/java/mage/abilities/condition/common/SourceHasCounterCondition.java
+++ b/Mage/src/main/java/mage/abilities/condition/common/SourceHasCounterCondition.java
@@ -1,86 +1,87 @@
-
package mage.abilities.condition.common;
import mage.abilities.Ability;
-import mage.abilities.condition.Condition;
-import mage.cards.Card;
+import mage.abilities.condition.IntCompareCondition;
+import mage.constants.ComparisonType;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
+import java.util.Optional;
+
/**
- * @author nantuko
+ * Don't use ComparisonType.OR_GREATER with value 0
+ *
+ * @author TheElk801
*/
-public class SourceHasCounterCondition implements Condition {
+public class SourceHasCounterCondition extends IntCompareCondition {
private final CounterType counterType;
- private int amount = 1;
- private int from = -1;
- private int to;
- public SourceHasCounterCondition(CounterType type) {
- this.counterType = type;
+ public SourceHasCounterCondition(CounterType counterType) {
+ this(counterType, 1);
}
- public SourceHasCounterCondition(CounterType type, int amount) {
- this.counterType = type;
- this.amount = amount;
+ public SourceHasCounterCondition(CounterType counterType, int amount) {
+ this(counterType, ComparisonType.OR_GREATER, amount);
}
- public SourceHasCounterCondition(CounterType type, int from, int to) {
- this.counterType = type;
- this.from = from;
- this.to = to;
+ public SourceHasCounterCondition(CounterType counterType, ComparisonType type, int value) {
+ super(type, value);
+ this.counterType = counterType;
}
@Override
- @SuppressWarnings("null")
- public boolean apply(Game game, Ability source) {
- Card card = null;
+ protected int getInputValue(Game game, Ability source) {
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
- if (permanent == null) {
- card = game.getCard(source.getSourceId());
- if (card == null) {
- return false;
- }
- }
- if (from != -1) { //range compare
- int count;
- if (card != null) {
- count = card.getCounters(game).getCount(counterType);
- } else {
- count = permanent.getCounters(game).getCount(counterType);
- }
- if (to == Integer.MAX_VALUE) {
- return count >= from;
- }
- return count >= from && count <= to;
- } else // single compare (lte)
- {
- if (card != null) {
- return card.getCounters(game).getCount(counterType) >= amount;
- } else {
- return permanent.getCounters(game).getCount(counterType) >= amount;
- }
+ if (permanent != null) {
+ return permanent.getCounters(game).getCount(counterType);
}
+ return Optional.ofNullable(source)
+ .map(Ability::getSourceId)
+ .map(game::getCard)
+ .map(card -> card.getCounters(game).getCount(counterType))
+ .orElse(0);
}
@Override
public String toString() {
- if (from != -1) {
- if (from == 0) {
- if (to == 0) {
- return "{this} has no " + this.counterType.toString() + " counters on it";
+ switch (type) {
+ case EQUAL_TO:
+ StringBuilder sb = new StringBuilder("there ");
+ switch (value) {
+ case 0:
+ sb.append("are no ");
+ break;
+ case 1:
+ sb.append("is exactly one ");
+ break;
+ default:
+ sb.append("are exactly ");
+ sb.append(CardUtil.numberToText(value));
+ sb.append(' ');
}
- return "{this} has " + CardUtil.numberToText(to) + " or fewer " + this.counterType.toString() + " counters on it";
- }
- if (to == Integer.MAX_VALUE) {
- return "{this} has " + CardUtil.numberToText(from) + " or more " + this.counterType.toString() + " counters on it";
- }
- return "{this} has between " + from + " and " + to + " " + this.counterType.toString() + " counters on it";
- } else {
- return "{this} has " + CardUtil.numberToText(amount) + " or more " + this.counterType.toString() + " counters on it";
+ sb.append(counterType.getName());
+ sb.append(" counter");
+ if (value != 1) {
+ sb.append('s');
+ }
+ sb.append(" on {this}");
+ return sb.toString();
+ case OR_GREATER:
+ if (value == 0) {
+ throw new IllegalArgumentException("0 or greater should not be used");
+ }
+ return "there are " + CardUtil.numberToText(value) + " or more " + counterType.getName() + " counters on {this}";
+ case OR_LESS:
+ return "{this} has " + CardUtil.numberToText(value) + " or fewer " + counterType.getName() + " counters on it";
+ case FEWER_THAN:
+ return "{this} has fewer than " + CardUtil.numberToText(value) + ' ' + counterType.getName() + " counters on it";
+ case MORE_THAN:
+ return "{this} has more than " + CardUtil.numberToText(value) + ' ' + counterType.getName() + " counters on it";
+ default:
+ throw new UnsupportedOperationException("There should be a comparison type");
}
}
}
diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceHasntDealtDamageThisGameCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceHasntDealtDamageThisGameCondition.java
new file mode 100644
index 00000000000..bd34c678443
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/condition/common/SourceHasntDealtDamageThisGameCondition.java
@@ -0,0 +1,34 @@
+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.DealtDamageThisGameWatcher;
+
+/**
+ * requires DealtDamageThisGameWatcher
+ *
+ * @author TheElk801
+ */
+public enum SourceHasntDealtDamageThisGameCondition implements Condition {
+ instance;
+ private static final Hint hint = new ConditionHint(
+ instance, "This creature hasn't dealt damage yet this game"
+ );
+
+ public static Hint getHint() {
+ return hint;
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ return DealtDamageThisGameWatcher.checkCreature(game, source);
+ }
+
+ @Override
+ public String toString() {
+ return "{this} hasn't dealt damage yet";
+ }
+}
diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java
index 6af8ad5ad4d..ddaf70e39f9 100644
--- a/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java
+++ b/Mage/src/main/java/mage/abilities/costs/common/RevealSourceFromYourHandCost.java
@@ -1,7 +1,5 @@
-
-
package mage.abilities.costs.common;
-import java.util.UUID;
+
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
@@ -12,18 +10,17 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
+import java.util.UUID;
+
/**
- *
- *
- *
* @author LevelX2
- *
*/
public class RevealSourceFromYourHandCost extends CostImpl {
public RevealSourceFromYourHandCost() {
- this.text = "reveal {this} from your hand";
+ this.text = "reveal this card from your hand";
}
+
public RevealSourceFromYourHandCost(RevealSourceFromYourHandCost cost) {
super(cost);
}
@@ -32,14 +29,16 @@ public class RevealSourceFromYourHandCost extends CostImpl {
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
paid = false;
Player player = game.getPlayer(controllerId);
- if (player != null) {
- Card card = player.getHand().get(ability.getSourceId(), game);
- if (card != null) {
- Cards cards = new CardsImpl(card);
- paid = true;
- player.revealCards("Reveal card cost", cards, game);
- }
+ if (player == null) {
+ return paid;
}
+ Card card = player.getHand().get(ability.getSourceId(), game);
+ if (card == null) {
+ return paid;
+ }
+ Cards cards = new CardsImpl(card);
+ paid = true;
+ player.revealCards("Reveal card cost", cards, game);
return paid;
}
@@ -52,5 +51,4 @@ public class RevealSourceFromYourHandCost extends CostImpl {
public RevealSourceFromYourHandCost copy() {
return new RevealSourceFromYourHandCost(this);
}
-
}
diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
index 67d2f1cce87..f975727ef27 100644
--- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
+++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java
@@ -131,6 +131,11 @@ public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityIm
ability.setSourceObjectZoneChangeCounter(sourceObjectZoneChangeCounter);
}
+ @Override
+ public void initSourceObjectZoneChangeCounter(Game game, boolean force) {
+ ability.initSourceObjectZoneChangeCounter(game, force);
+ }
+
@Override
public int getSourceObjectZoneChangeCounter() {
return ability.getSourceObjectZoneChangeCounter();
diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaValueInGraveyard.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaValueInGraveyard.java
index 752a637cde0..97a0fae8e9d 100644
--- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaValueInGraveyard.java
+++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaValueInGraveyard.java
@@ -46,7 +46,7 @@ public class ManaValueInGraveyard implements DynamicValue {
return 0;
}
int value = player.getGraveyard().stream().map(game::getCard).filter(Objects::nonNull)
- .filter(card -> filter.match(card, playerId, game)).mapToInt(MageObject::getManaValue).sum();
+ .filter(card -> filter.match(card, playerId, sourceAbility, game)).mapToInt(MageObject::getManaValue).sum();
if (multiplier != null) {
value *= multiplier;
}
diff --git a/Mage/src/main/java/mage/abilities/effects/Effects.java b/Mage/src/main/java/mage/abilities/effects/Effects.java
index fbfdaf7ba5a..3486b664e15 100644
--- a/Mage/src/main/java/mage/abilities/effects/Effects.java
+++ b/Mage/src/main/java/mage/abilities/effects/Effects.java
@@ -8,6 +8,7 @@ import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Optional;
/**
* @author BetaSteward_at_googlemail.com
@@ -29,11 +30,21 @@ public class Effects extends ArrayList {
}
public String getTextStartingUpperCase(Mode mode) {
- String text = getText(mode);
- if (text.length() > 3) {
- return CardUtil.getTextWithFirstCharUpperCase(text);
+ StringBuilder text = Optional
+ .of(getText(mode))
+ .map(s -> s.length() > 3 ? CardUtil.getTextWithFirstCharUpperCase(s) : s)
+ .map(StringBuilder::new)
+ .get();
+ // cost
+ if (mode.getCost() != null) {
+ text.insert(0, " — ");
+ text.insert(0, mode.getCost().getText());
}
- return text;
+ // flavor word
+ if (mode.getFlavorWord() != null) {
+ text.insert(0, CardUtil.italicizeWithEmDash(mode.getFlavorWord()));
+ }
+ return text.toString();
}
public String getText(Mode mode) {
@@ -115,20 +126,6 @@ public class Effects extends ArrayList {
sbText.append('.');
}
-
- if (mode.getCost() != null || mode.getFlavorWord() != null) {
- sbText.replace(0, 1, sbText.substring(0, 1).toUpperCase());
- }
- // cost
- if (mode.getCost() != null) {
- sbText.insert(0, " — ");
- sbText.insert(0, mode.getCost().getText());
- }
- // flavor word
- if (mode.getFlavorWord() != null) {
- sbText.insert(0, CardUtil.italicizeWithEmDash(mode.getFlavorWord()));
- }
-
return sbText.toString();
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java
index f3eba38d1c1..bcc3e11aa63 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureEffect.java
@@ -48,6 +48,9 @@ public class ChooseCreatureEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId());
+ if (sourcePermanent == null) {
+ sourcePermanent = game.getPermanent(source.getSourceId());
+ }
if (controller == null || sourcePermanent == null) {
return false;
}
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 c531d1fc39c..ae23687ce8a 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java
@@ -172,12 +172,17 @@ public class DamageTargetEffect extends OneShotEffect {
} else {
if (firstTarget.getMinNumberOfTargets() == 0) {
int maxTargets = firstTarget.getMaxNumberOfTargets();
- if (maxTargets == Integer.MAX_VALUE) {
- sb.append("any number of ");
- } else {
- sb.append("each of up to ");
- sb.append(CardUtil.numberToText(maxTargets));
- sb.append(' ');
+ 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 ")) {
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java
index a6b0234d495..9a9a32d454c 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java
@@ -9,6 +9,7 @@ import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
+import mage.util.CardUtil;
/**
* @author LevelX2
@@ -20,7 +21,7 @@ public class ExileCardYouChooseTargetOpponentEffect extends OneShotEffect {
public ExileCardYouChooseTargetOpponentEffect(FilterCard filter) {
super(Outcome.Discard);
this.staticText = "target opponent reveals their hand. You choose "
- + filter.getMessage() + (filter.getMessage().contains("from it") ? "" : " from it") + " and exile that card";
+ + CardUtil.addArticle(filter.getMessage()) + (filter.getMessage().contains("from it") ? "" : " from it") + " and exile that card";
this.filter = filter;
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java
index 8c404a46482..edc5433bba3 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java
@@ -12,9 +12,6 @@ import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import mage.players.Player;
-import mage.target.Target;
-import mage.target.targetpointer.FirstTargetPointer;
-import mage.target.targetpointer.SecondTargetPointer;
import mage.util.CardUtil;
import java.util.LinkedHashSet;
@@ -27,8 +24,8 @@ import java.util.UUID;
public class ExileTargetEffect extends OneShotEffect {
private final Zone onlyFromZone;
- private String exileZone = null;
- private UUID exileId = null;
+ protected String exileZone = null;
+ protected UUID exileId = null;
private boolean toSourceExileZone = false; // exile the targets to a source object specific exile zone (takes care of zone change counter)
private boolean withName = true; // for face down - allows to hide card name in game logs before real face down apply
diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java
index 455cba7d14e..60e0232529c 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/PutSourceCountersOnTargetEffect.java
@@ -27,7 +27,7 @@ public class PutSourceCountersOnTargetEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
- Permanent sourcePermanent = (Permanent) getValue("permanentLeftBattlefield");
+ Permanent sourcePermanent = source.getSourcePermanentOrLKI(game);
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (sourcePermanent == null || permanent == null) {
return false;
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
index 5d3f0b1bea0..078e2b09e91 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java
@@ -7,10 +7,11 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
+import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
+import java.util.stream.Collectors;
/**
* @author emerald000
@@ -76,19 +77,20 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl {
}
StringBuilder sb = new StringBuilder();
sb.append("{this} becomes ");
- boolean article = false;
- for (CardType cardType : addedCardTypes) {
- if (!article) {
- if (cardType.toString().startsWith("A") || cardType.toString().startsWith("E")) {
- sb.append("an ");
- } else {
- sb.append("a ");
- }
- article = true;
- }
- sb.append(cardType.toString().toLowerCase(Locale.ENGLISH)).append(" ");
+ sb.append(CardUtil.addArticle(
+ addedCardTypes
+ .stream()
+ .map(CardType::toString)
+ .map(String::toLowerCase)
+ .collect(Collectors.joining(" "))
+ ));
+ if (!addedCardTypes.contains(CardType.ARTIFACT) || !addedCardTypes.contains(CardType.CREATURE)) {
+ sb.append(" in addition to its other types");
+ }
+ if (!this.getDuration().toString().isEmpty()) {
+ sb.append(' ');
+ sb.append(this.getDuration());
}
- sb.append("in addition to its other types ").append(this.getDuration().toString());
return sb.toString();
}
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesTargetEffect.java
index 614be0bd431..81431bc87d3 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesTargetEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesTargetEffect.java
@@ -51,7 +51,7 @@ public class LoseAllAbilitiesTargetEffect extends ContinuousEffectImpl {
return staticText;
}
return getTargetPointer().describeTargets(mode.getTargets(), "it")
- + " loses all abilities " + (duration.toString().isEmpty() ? "" : ' ' + duration.toString());
+ + " loses all abilities" + (duration.toString().isEmpty() ? "" : ' ' + duration.toString());
}
}
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/WUBRGInsteadEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/WUBRGInsteadEffect.java
index ef516b424f0..1e6ed210a2c 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/WUBRGInsteadEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/WUBRGInsteadEffect.java
@@ -25,7 +25,7 @@ public class WUBRGInsteadEffect extends ContinuousEffectImpl {
public WUBRGInsteadEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
- staticText = "You may pay {W}{U}{B}{R}{G} rather than pay the mana cost for spells that you cast";
+ staticText = "You may pay {W}{U}{B}{R}{G} rather than pay the mana cost for spells you cast";
}
protected WUBRGInsteadEffect(final WUBRGInsteadEffect effect) {
diff --git a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
index 1fd68ab47dc..6349655d944 100644
--- a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
@@ -21,7 +21,6 @@ import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import mage.util.CardUtil;
-import java.util.Objects;
import java.util.UUID;
/*
@@ -188,13 +187,9 @@ class ConspireTriggeredAbility extends CastSourceTriggeredAbility {
return false;
}
Spell spell = game.getStack().getSpell(event.getSourceId());
- return spell != null
- && spell
- .getSpellAbility()
- .getAllEffects()
- .stream()
- .map(effect -> effect.getValue("ConspireActivation" + conspireId + addedById))
- .anyMatch(Objects::nonNull);
+ return spell != null && CardUtil.getEffectValueFromAbility(
+ spell.getSpellAbility(), "ConspireActivation" + conspireId + addedById, Boolean.class
+ ).orElse(false);
}
@Override
diff --git a/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java
index c14e5336849..4ca62852bbc 100644
--- a/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java
@@ -1,12 +1,10 @@
package mage.abilities.keyword;
-import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.EvokedCondition;
import mage.abilities.costs.AlternativeSourceCostsImpl;
import mage.abilities.costs.Cost;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.SacrificeSourceEffect;
/**
@@ -24,11 +22,9 @@ public class EvokeAbility extends AlternativeSourceCostsImpl {
public EvokeAbility(Cost cost) {
super(EVOKE_KEYWORD, REMINDER_TEXT, cost);
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new SacrificeSourceEffect(true)),
- EvokedCondition.instance, "When this permanent enters the battlefield, if its evoke cost was paid, its controller sacrifices it.");
- ability.setRuleVisible(false);
- addSubAbility(ability);
+ this.addSubAbility(new EntersBattlefieldTriggeredAbility(
+ new SacrificeSourceEffect(true).setText("its controller sacrifices it")
+ ).setTriggerPhrase("When this permanent enters, ").withInterveningIf(EvokedCondition.instance).setRuleVisible(false));
}
private EvokeAbility(final EvokeAbility ability) {
@@ -40,7 +36,7 @@ public class EvokeAbility extends AlternativeSourceCostsImpl {
return new EvokeAbility(this);
}
- public static String getActivationKey(){
+ public static String getActivationKey() {
return getActivationKey(EVOKE_KEYWORD);
}
}
diff --git a/Mage/src/main/java/mage/abilities/keyword/EvolveAbility.java b/Mage/src/main/java/mage/abilities/keyword/EvolveAbility.java
index 09fb8dee62a..a80bb2c43ce 100644
--- a/Mage/src/main/java/mage/abilities/keyword/EvolveAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/EvolveAbility.java
@@ -10,6 +10,7 @@ import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
+import mage.util.CardUtil;
/**
* FAQ 2013/01/11
@@ -75,18 +76,14 @@ public class EvolveAbility extends EntersBattlefieldAllTriggeredAbility {
@Override
public boolean checkInterveningIfClause(Game game) {
Permanent sourcePermanent = getSourcePermanentOrLKI(game);
- Permanent permanentEntering = (Permanent) this
- .getEffects()
- .stream()
- .map(effect -> effect.getValue("permanentEnteringBattlefield"))
- .findFirst()
- .orElse(null);
return sourcePermanent != null
- && permanentEntering != null
&& sourcePermanent.isCreature(game)
- && permanentEntering.isCreature(game)
- && (permanentEntering.getPower().getValue() > sourcePermanent.getPower().getValue()
- || permanentEntering.getToughness().getValue() > sourcePermanent.getToughness().getValue());
+ && CardUtil
+ .getEffectValueFromAbility(this, "permanentEnteringBattlefield", Permanent.class)
+ .filter(permanent -> permanent.isCreature(game))
+ .filter(permanent -> sourcePermanent.getPower().getValue() < permanent.getPower().getValue()
+ || sourcePermanent.getToughness().getValue() < permanent.getToughness().getValue())
+ .isPresent();
}
@Override
diff --git a/Mage/src/main/java/mage/abilities/keyword/ExhaustAbility.java b/Mage/src/main/java/mage/abilities/keyword/ExhaustAbility.java
index f8cd4e3f532..c34fcfc2a6c 100644
--- a/Mage/src/main/java/mage/abilities/keyword/ExhaustAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/ExhaustAbility.java
@@ -12,15 +12,14 @@ import mage.game.Game;
*/
public class ExhaustAbility extends ActivatedAbilityImpl {
- private boolean withReminderText = true;
+ private final boolean withReminderText;
public ExhaustAbility(Effect effect, Cost cost) {
- super(Zone.BATTLEFIELD, effect, cost);
+ this(effect, cost, true);
}
public ExhaustAbility(Effect effect, Cost cost, boolean withReminderText) {
super(Zone.BATTLEFIELD, effect, cost);
- this.setRuleVisible(false);
this.withReminderText = withReminderText;
}
@@ -30,11 +29,6 @@ public class ExhaustAbility extends ActivatedAbilityImpl {
this.withReminderText = ability.withReminderText;
}
- public ExhaustAbility withReminderText(boolean withReminderText) {
- this.withReminderText = withReminderText;
- return this;
- }
-
@Override
public ExhaustAbility copy() {
return new ExhaustAbility(this);
@@ -45,8 +39,8 @@ public class ExhaustAbility extends ActivatedAbilityImpl {
ActivationInfo info = getActivationInfo(game);
if (info != null && info.totalActivations >= maxActivationsPerGame) {
boolean canActivate = !game.getContinuousEffects()
- .asThough(sourceId, AsThoughEffectType.ALLOW_EXHAUST_PER_TURN, this, controllerId, game)
- .isEmpty();
+ .asThough(sourceId, AsThoughEffectType.ALLOW_EXHAUST_PER_TURN, this, controllerId, game)
+ .isEmpty();
if (canActivate) {
return true;
}
diff --git a/Mage/src/main/java/mage/abilities/keyword/GiftAbility.java b/Mage/src/main/java/mage/abilities/keyword/GiftAbility.java
index 7070eb9bd89..f0909d8cb47 100644
--- a/Mage/src/main/java/mage/abilities/keyword/GiftAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/GiftAbility.java
@@ -6,7 +6,6 @@ import mage.abilities.StaticAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.GiftWasPromisedCondition;
import mage.abilities.costs.*;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.GiftType;
@@ -53,11 +52,10 @@ public class GiftAbility extends StaticAbility implements OptionalAdditionalSour
this.rule = additionalCost.getName() + ' ' + additionalCost.getReminderText();
this.setRuleAtTheTop(true);
if (card.isPermanent()) {
- this.addSubAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new PromiseGiftEffect(giftType)),
- GiftWasPromisedCondition.TRUE, "When this permanent enters, " +
- "if the gift was promised, they " + giftType.getDescription() + '.'
- ).setRuleVisible(false));
+ this.addSubAbility(new EntersBattlefieldTriggeredAbility(new PromiseGiftEffect(giftType))
+ .setTriggerPhrase("When this permanent enters, ")
+ .withInterveningIf(GiftWasPromisedCondition.TRUE)
+ .setRuleVisible(false));
} else {
card.getSpellAbility().addEffect(new PromiseGiftEffect(giftType));
}
@@ -154,6 +152,7 @@ class PromiseGiftEffect extends OneShotEffect {
PromiseGiftEffect(GiftType giftType) {
super(Outcome.Benefit);
this.giftType = giftType;
+ staticText = "they " + giftType.getDescription();
}
private PromiseGiftEffect(final PromiseGiftEffect effect) {
diff --git a/Mage/src/main/java/mage/abilities/keyword/ImpendingAbility.java b/Mage/src/main/java/mage/abilities/keyword/ImpendingAbility.java
index 63cf3019712..647cff7afd4 100644
--- a/Mage/src/main/java/mage/abilities/keyword/ImpendingAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/ImpendingAbility.java
@@ -1,7 +1,6 @@
package mage.abilities.keyword;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
@@ -13,6 +12,7 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.AddContinuousEffectToGame;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
+import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
@@ -37,7 +37,7 @@ public class ImpendingAbility extends AlternativeSourceCostsImpl {
private static final String IMPENDING_REMINDER = "If you cast this spell for its impending cost, " +
"it enters with %s time counters and isn't a creature until the last is removed. " +
"At the beginning of your end step, remove a time counter from it.";
- private static final Condition counterCondition = new SourceHasCounterCondition(CounterType.TIME, 0, 0);
+ private static final Condition counterCondition = new SourceHasCounterCondition(CounterType.TIME, ComparisonType.EQUAL_TO, 0);
public ImpendingAbility(int amount, String manaString) {
super(IMPENDING_KEYWORD + ' ' + amount, String.format(IMPENDING_REMINDER, CardUtil.numberToText(amount)), new ManaCostsImpl<>(manaString), IMPENDING_KEYWORD);
diff --git a/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java b/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java
index 7c28881cfdf..cf5bf334ca5 100644
--- a/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java
+++ b/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java
@@ -4,14 +4,15 @@ import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect;
+import mage.constants.ComparisonType;
import mage.constants.Duration;
-import mage.constants.Zone;
import mage.counters.CounterType;
import java.util.ArrayList;
@@ -46,7 +47,11 @@ public class LevelerCardBuilder {
public List build() {
List constructed = new ArrayList<>();
- Condition condition = new SourceHasCounterCondition(CounterType.LEVEL, level1, level2);
+ Condition condition = new CompoundCondition(
+ "",
+ new SourceHasCounterCondition(CounterType.LEVEL, ComparisonType.OR_GREATER, level1),
+ new SourceHasCounterCondition(CounterType.LEVEL, ComparisonType.OR_LESS, level2)
+ );
for (Ability ability : abilities) {
ContinuousEffect effect = new GainAbilitySourceEffect(ability);
ConditionalContinuousEffect abEffect = new ConditionalContinuousEffect(effect, condition, "");
diff --git a/Mage/src/main/java/mage/abilities/keyword/OffspringAbility.java b/Mage/src/main/java/mage/abilities/keyword/OffspringAbility.java
index 9888c995dde..8be10098297 100644
--- a/Mage/src/main/java/mage/abilities/keyword/OffspringAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/OffspringAbility.java
@@ -7,7 +7,6 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.*;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.constants.Outcome;
@@ -43,10 +42,8 @@ public class OffspringAbility extends StaticAbility implements OptionalAdditiona
this.additionalCost.setRepeatable(false);
this.rule = additionalCost.getName() + ' ' + additionalCost.getReminderText();
this.setRuleAtTheTop(true);
- this.addSubAbility(new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new OffspringEffect()), OffspringCondition.instance,
- "When this creature enters, if its offspring cost was paid, create a 1/1 token copy of it."
- ).setRuleVisible(false));
+ this.addSubAbility(new EntersBattlefieldTriggeredAbility(new OffspringEffect())
+ .withInterveningIf(OffspringCondition.instance).setRuleVisible(false));
}
private OffspringAbility(final OffspringAbility ability) {
@@ -96,6 +93,7 @@ class OffspringEffect extends OneShotEffect {
OffspringEffect() {
super(Outcome.Benefit);
+ staticText = "create a 1/1 token copy of it";
}
private OffspringEffect(final OffspringEffect effect) {
@@ -127,6 +125,6 @@ enum OffspringCondition implements Condition {
@Override
public String toString() {
- return "Offspring cost was paid";
+ return "its offspring cost was paid";
}
}
diff --git a/Mage/src/main/java/mage/abilities/keyword/RavenousAbility.java b/Mage/src/main/java/mage/abilities/keyword/RavenousAbility.java
index 77cbbdc64e0..5d98d9b150b 100644
--- a/Mage/src/main/java/mage/abilities/keyword/RavenousAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/RavenousAbility.java
@@ -4,7 +4,6 @@ import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect;
@@ -18,13 +17,8 @@ public class RavenousAbility extends EntersBattlefieldAbility {
public RavenousAbility() {
super(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()));
- Ability ability = new ConditionalInterveningIfTriggeredAbility(
- new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)),
- RavenousAbilityCondition.instance, "When this creature enters, " +
- "if X is 5 or more, draw a card"
- );
- ability.setRuleVisible(false);
- this.addSubAbility(ability);
+ this.addSubAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))
+ .withInterveningIf(RavenousAbilityCondition.instance).setRuleVisible(false));
}
private RavenousAbility(final RavenousAbility ability) {
@@ -50,4 +44,9 @@ enum RavenousAbilityCondition implements Condition {
public boolean apply(Game game, Ability source) {
return GetXValue.instance.calculate(game, source, null) >= 5;
}
+
+ @Override
+ public String toString() {
+ return "X is 5 or more";
+ }
}
diff --git a/Mage/src/main/java/mage/cards/CardsImpl.java b/Mage/src/main/java/mage/cards/CardsImpl.java
index b4f748b29a4..92205a199c3 100644
--- a/Mage/src/main/java/mage/cards/CardsImpl.java
+++ b/Mage/src/main/java/mage/cards/CardsImpl.java
@@ -99,7 +99,7 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl
@Override
public int count(FilterCard filter, UUID playerId, Game game) {
- return (int) this.stream().filter(card -> filter.match(game.getCard(card), playerId, game)).count();
+ return (int) this.stream().filter(card -> filter.match(game.getCard(card), playerId, null, game)).count();
}
diff --git a/Mage/src/main/java/mage/filter/FilterCard.java b/Mage/src/main/java/mage/filter/FilterCard.java
index c101228703d..e7aa44a073c 100644
--- a/Mage/src/main/java/mage/filter/FilterCard.java
+++ b/Mage/src/main/java/mage/filter/FilterCard.java
@@ -9,9 +9,7 @@ import mage.game.Game;
import java.util.ArrayList;
import java.util.List;
-import java.util.Set;
import java.util.UUID;
-import java.util.stream.Collectors;
/**
* Works with cards only. For objects like commanders you must override your canTarget method.
@@ -40,14 +38,6 @@ public class FilterCard extends FilterObject {
return new FilterCard(this);
}
- public boolean match(Card card, UUID playerId, Game game) {
- return match(card, playerId, null, game);
- }
-
- public Set filter(Set cards, Game game) {
- return cards.stream().filter(card -> match(card, game)).collect(Collectors.toSet());
- }
-
public static void checkPredicateIsSuitableForCardFilter(Predicate predicate) {
// card filter can't contain controller predicate (only permanents on battlefield and StackObjects have controller)
List list = new ArrayList<>();
diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java
index 33903843f47..201c60fc726 100644
--- a/Mage/src/main/java/mage/filter/StaticFilters.java
+++ b/Mage/src/main/java/mage/filter/StaticFilters.java
@@ -24,12 +24,6 @@ public final class StaticFilters {
private StaticFilters() {
}
- public static final FilterSpiritOrArcaneCard FILTER_SPIRIT_OR_ARCANE_CARD = new FilterSpiritOrArcaneCard();
-
- static {
- FILTER_SPIRIT_OR_ARCANE_CARD.setLockedFilter(true);
- }
-
public static final FilterCard FILTER_CARD = new FilterCard("card");
static {
@@ -158,24 +152,20 @@ public final class StaticFilters {
FILTER_CARD_CREATURE_A_GRAVEYARD.setLockedFilter(true);
}
- public static final FilterNoncreatureCard FILTER_CARD_NON_CREATURE = new FilterNoncreatureCard();
+ public static final FilterCard FILTER_CARD_NON_CREATURE = new FilterCard();
static {
+ FILTER_CARD_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate()));
FILTER_CARD_NON_CREATURE.setLockedFilter(true);
}
- public static final FilterNoncreatureCard FILTER_CARD_A_NON_CREATURE = new FilterNoncreatureCard("a noncreature card");
+ public static final FilterCard FILTER_CARD_A_NON_CREATURE = new FilterCard("a noncreature card");
static {
+ FILTER_CARD_A_NON_CREATURE.add(Predicates.not(CardType.CREATURE.getPredicate()));
FILTER_CARD_A_NON_CREATURE.setLockedFilter(true);
}
- public static final FilterNoncreatureCard FILTER_CARDS_NON_CREATURE = new FilterNoncreatureCard("noncreature cards");
-
- static {
- FILTER_CARDS_NON_CREATURE.setLockedFilter(true);
- }
-
public static final FilterLandCard FILTER_CARD_LAND = new FilterLandCard();
static {
@@ -520,9 +510,13 @@ public final class StaticFilters {
FILTER_CONTROLLED_PERMANENT_LANDS.setLockedFilter(true);
}
- public static final FilterPermanent FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER = new FilterControlledCreatureOrPlaneswalkerPermanent("creature or planeswalker you control");
+ public static final FilterPermanent FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER = new FilterControlledPermanent("creature or planeswalker you control");
static {
+ FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER.add(Predicates.or(
+ CardType.CREATURE.getPredicate(),
+ CardType.PLANESWALKER.getPredicate()
+ ));
FILTER_CONTROLLED_PERMANENT_CREATURE_OR_PLANESWALKER.setLockedFilter(true);
}
@@ -1047,12 +1041,30 @@ public final class StaticFilters {
FILTER_SPELL_AN_ENCHANTMENT.setLockedFilter(true);
}
- public static final FilterSpell FILTER_SPELL_AN_ARTIFACT = new FilterArtifactSpell("an artifact spell");
+ public static final FilterSpell FILTER_SPELL_AN_ARTIFACT = new FilterSpell("an artifact spell");
static {
+ FILTER_SPELL_AN_ARTIFACT.add(CardType.ARTIFACT.getPredicate());
FILTER_SPELL_AN_ARTIFACT.setLockedFilter(true);
}
+ public static final FilterSpell FILTER_SPELL_SPIRIT_OR_ARCANE = new FilterSpell("a Spirit or Arcane spell");
+
+ static {
+ FILTER_SPELL_SPIRIT_OR_ARCANE.add(Predicates.or(
+ SubType.SPIRIT.getPredicate(),
+ SubType.ARCANE.getPredicate()
+ ));
+ FILTER_SPELL_SPIRIT_OR_ARCANE.setLockedFilter(true);
+ }
+
+ public static final FilterSpell FILTER_SPELL_HISTORIC = new FilterSpell("a historic spell");
+
+ static {
+ FILTER_SPELL_HISTORIC.add(HistoricPredicate.instance);
+ FILTER_SPELL_HISTORIC.setLockedFilter(true);
+ }
+
public static final FilterSpell FILTER_SPELL_KICKED_A = new FilterSpell("a kicked spell");
static {
diff --git a/Mage/src/main/java/mage/filter/common/FilterArtifactSpell.java b/Mage/src/main/java/mage/filter/common/FilterArtifactSpell.java
deleted file mode 100644
index dda5d74a7fb..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterArtifactSpell.java
+++ /dev/null
@@ -1,21 +0,0 @@
-
-package mage.filter.common;
-
-import mage.constants.CardType;
-import mage.filter.FilterSpell;
-
-/**
- *
- * @author Jgod
- */
-public class FilterArtifactSpell extends FilterSpell {
-
- public FilterArtifactSpell() {
- this("artifact spell");
- }
-
- public FilterArtifactSpell(String name) {
- super(name);
- this.add(CardType.ARTIFACT.getPredicate());
- }
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterControlledCreatureOrPlaneswalkerPermanent.java b/Mage/src/main/java/mage/filter/common/FilterControlledCreatureOrPlaneswalkerPermanent.java
deleted file mode 100644
index 44c62344baf..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterControlledCreatureOrPlaneswalkerPermanent.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package mage.filter.common;
-
-import mage.constants.CardType;
-import mage.constants.SubType;
-import mage.filter.predicate.Predicates;
-
-/**
- * @author LevelX2
- */
-public class FilterControlledCreatureOrPlaneswalkerPermanent extends FilterControlledPermanent {
-
- public FilterControlledCreatureOrPlaneswalkerPermanent() {
- this("creature or planeswalker you control");
- }
-
- public FilterControlledCreatureOrPlaneswalkerPermanent(SubType subType) {
- this(subType, "a " + subType + " creature or a " + subType + " planeswalker");
- }
-
- public FilterControlledCreatureOrPlaneswalkerPermanent(SubType subType, String name) {
- super(name);
- this.add(Predicates.or(
- CardType.CREATURE.getPredicate(),
- CardType.PLANESWALKER.getPredicate()
- ));
- this.add(subType.getPredicate());
- }
-
- public FilterControlledCreatureOrPlaneswalkerPermanent(String name) {
- super(name);
- this.add(Predicates.or(
- CardType.CREATURE.getPredicate(),
- CardType.PLANESWALKER.getPredicate()
- ));
- }
-
- protected FilterControlledCreatureOrPlaneswalkerPermanent(final FilterControlledCreatureOrPlaneswalkerPermanent filter) {
- super(filter);
- }
-
- @Override
- public FilterControlledCreatureOrPlaneswalkerPermanent copy() {
- return new FilterControlledCreatureOrPlaneswalkerPermanent(this);
- }
-
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java
deleted file mode 100644
index 358d4771c13..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-package mage.filter.common;
-
-import mage.abilities.keyword.DefenderAbility;
-import mage.filter.predicate.Predicate;
-import mage.filter.predicate.Predicates;
-import mage.filter.predicate.mageobject.AbilityPredicate;
-import mage.filter.predicate.permanent.AttackingPredicate;
-import mage.filter.predicate.permanent.BlockingPredicate;
-import mage.filter.predicate.permanent.TappedPredicate;
-import mage.game.Game;
-import mage.game.permanent.Permanent;
-
-/**
- * @author BetaSteward_at_googlemail.com
- * @author North
- */
-public class FilterCreatureForAttack extends FilterCreaturePermanent {
-
- public FilterCreatureForAttack() {
- this("");
- }
-
- public FilterCreatureForAttack(String name) {
- super(name);
- this.add(Predicates.not(AttackingPredicate.instance));
- this.add(Predicates.not(BlockingPredicate.instance));
- this.add(TappedPredicate.UNTAPPED);
- this.add(Predicates.not(new AbilityPredicate(DefenderAbility.class)));
- this.add(new CanTapPredicate());
- }
-
- protected FilterCreatureForAttack(final FilterCreatureForAttack filter) {
- super(filter);
- }
-
- @Override
- public FilterCreatureForAttack copy() {
- return new FilterCreatureForAttack(this);
- }
-}
-
-class CanTapPredicate implements Predicate {
-
- @Override
- public boolean apply(Permanent input, Game game) {
- return input.canTap(game);
- }
-
- @Override
- public String toString() {
- return "CanTap";
- }
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java b/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java
deleted file mode 100644
index 159fef4a66b..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package mage.filter.common;
-
-import mage.filter.FilterCard;
-import mage.filter.predicate.mageobject.HistoricPredicate;
-
-/**
- * @author LevelX2
- */
-public class FilterHistoricCard extends FilterCard {
-
- public FilterHistoricCard() {
- this("historic card");
- }
-
- public FilterHistoricCard(String name) {
- super(name);
- this.add(HistoricPredicate.instance);
- }
-
- protected FilterHistoricCard(final FilterHistoricCard filter) {
- super(filter);
- }
-
- @Override
- public FilterHistoricCard copy() {
- return new FilterHistoricCard(this);
- }
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java b/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java
deleted file mode 100644
index df3cb607d1a..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package mage.filter.common;
-
-import mage.filter.FilterSpell;
-import mage.filter.predicate.mageobject.HistoricPredicate;
-
-/**
- * @author igoudt
- */
-public class FilterHistoricSpell extends FilterSpell {
-
- public FilterHistoricSpell() {
- super("a historic spell");
- this.add(HistoricPredicate.instance);
- }
-
- protected FilterHistoricSpell(final FilterHistoricSpell filter) {
- super(filter);
- }
-
- @Override
- public FilterHistoricSpell copy() {
- return new FilterHistoricSpell(this);
- }
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterInstantSpell.java b/Mage/src/main/java/mage/filter/common/FilterInstantSpell.java
deleted file mode 100644
index 0982049952b..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterInstantSpell.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package mage.filter.common;
-
-import mage.constants.CardType;
-import mage.filter.FilterSpell;
-
-public class FilterInstantSpell extends FilterSpell {
-
- public FilterInstantSpell() {
- this("instant spell");
- }
-
- public FilterInstantSpell(String name) {
- super(name);
- this.add(CardType.INSTANT.getPredicate());
- }
-
- protected FilterInstantSpell(final FilterInstantSpell filter) {
- super(filter);
- }
-
- @Override
- public FilterInstantSpell copy() {
- return new FilterInstantSpell(this);
- }
-
-}
\ No newline at end of file
diff --git a/Mage/src/main/java/mage/filter/common/FilterNoncreatureCard.java b/Mage/src/main/java/mage/filter/common/FilterNoncreatureCard.java
deleted file mode 100644
index 496b26863c2..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterNoncreatureCard.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package mage.filter.common;
-
-import mage.constants.CardType;
-import mage.filter.FilterCard;
-import mage.filter.predicate.Predicates;
-
-/**
- * @author ssouders412
- */
-public class FilterNoncreatureCard extends FilterCard {
-
- public FilterNoncreatureCard() {
- this("noncreature card");
- }
-
- public FilterNoncreatureCard(String name) {
- super(name);
- this.add(Predicates.not(CardType.CREATURE.getPredicate()));
- }
-
- protected FilterNoncreatureCard(final FilterNoncreatureCard filter) {
- super(filter);
- }
-
- @Override
- public FilterNoncreatureCard copy() {
- return new FilterNoncreatureCard(this);
- }
-}
diff --git a/Mage/src/main/java/mage/filter/common/FilterSpiritOrArcaneCard.java b/Mage/src/main/java/mage/filter/common/FilterSpiritOrArcaneCard.java
deleted file mode 100644
index ce187aefdc1..00000000000
--- a/Mage/src/main/java/mage/filter/common/FilterSpiritOrArcaneCard.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package mage.filter.common;
-
-import mage.constants.SubType;
-import mage.filter.FilterSpell;
-import mage.filter.predicate.Predicates;
-
-public class FilterSpiritOrArcaneCard extends FilterSpell {
-
- public FilterSpiritOrArcaneCard() {
- this("a Spirit or Arcane spell");
- }
-
- public FilterSpiritOrArcaneCard(String name) {
- super(name);
- this.add(Predicates.or(SubType.SPIRIT.getPredicate(), SubType.ARCANE.getPredicate()));
- }
-
- protected FilterSpiritOrArcaneCard(final FilterSpiritOrArcaneCard filter) {
- super(filter);
- }
-
- @Override
- public FilterSpiritOrArcaneCard copy() {
- return new FilterSpiritOrArcaneCard(this);
- }
-}
diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java
index 63147190c01..06932787520 100644
--- a/Mage/src/main/java/mage/game/GameImpl.java
+++ b/Mage/src/main/java/mage/game/GameImpl.java
@@ -1960,7 +1960,7 @@ public abstract class GameImpl implements Game {
@Override
public void addEffect(ContinuousEffect continuousEffect, Ability source) {
Ability newAbility = source.copy();
- newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId()));
+ newAbility.initSourceObjectZoneChangeCounter(this, true);
ContinuousEffect newEffect = continuousEffect.copy();
newEffect.newId();
@@ -2159,18 +2159,14 @@ public abstract class GameImpl implements Game {
// countered, or otherwise responded to. Rather, it resolves immediately after the mana
// ability that triggered it, without waiting for priority.
Ability manaAbility = ability.copy();
- if (manaAbility.getSourceObjectZoneChangeCounter() == 0) {
- manaAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
- }
+ manaAbility.initSourceObjectZoneChangeCounter(this, false);
if (manaAbility.activate(this, false)) {
manaAbility.resolve(this);
}
} else {
TriggeredAbility newAbility = ability.copy();
newAbility.newId();
- if (newAbility.getSourceObjectZoneChangeCounter() == 0) {
- newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId()));
- }
+ newAbility.initSourceObjectZoneChangeCounter(this, false);
if (!(newAbility instanceof DelayedTriggeredAbility)) {
newAbility.setSourcePermanentTransformCount(this);
}
@@ -2715,9 +2711,9 @@ public abstract class GameImpl implements Game {
.add(perm);
}
}
- // 704.5s If the number of lore counters on a Saga permanent is greater than or equal to its final chapter number
+ // 704.5s If the number of lore counters on a Saga permanent with one or more chapter abilities is greater than or equal to its final chapter number
// and it isn't the source of a chapter ability that has triggered but not yet left the stack, that Saga's controller sacrifices it.
- if (perm.hasSubtype(SubType.SAGA, this)) {
+ if (perm.hasSubtype(SubType.SAGA, this) && perm.getAbilities(this).containsClass(SagaAbility.class)) {
int maxChapter = perm
.getAbilities(this)
.stream()
diff --git a/Mage/src/main/java/mage/game/command/emblems/ArlinnEmbracedByTheMoonEmblem.java b/Mage/src/main/java/mage/game/command/emblems/ArlinnEmbracedByTheMoonEmblem.java
index d722d1e07ce..5606f00850c 100644
--- a/Mage/src/main/java/mage/game/command/emblems/ArlinnEmbracedByTheMoonEmblem.java
+++ b/Mage/src/main/java/mage/game/command/emblems/ArlinnEmbracedByTheMoonEmblem.java
@@ -33,7 +33,7 @@ public final class ArlinnEmbracedByTheMoonEmblem extends Emblem {
Ability ability2 = new SimpleActivatedAbility(effect2, new TapSourceCost());
ability2.addTarget(new TargetAnyTarget());
effect = new GainAbilityControlledEffect(ability2, Duration.EndOfGame, filter);
- effect.setText("and '{T}: This creature deals damage equal to its power to any target");
+ effect.setText("and '{T}: This creature deals damage equal to its power to any target'");
ability.addEffect(effect);
this.getAbilities().add(ability);
}
diff --git a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java
index b45be6875a4..9e775d88d92 100644
--- a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java
+++ b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java
@@ -3,7 +3,6 @@ package mage.game.command.emblems;
import mage.abilities.Ability;
import mage.abilities.common.OneOrMoreCombatDamagePlayerTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
@@ -25,13 +24,9 @@ public final class LolthSpiderQueenEmblem extends Emblem {
// −8: You get an emblem with "Whenever an opponent is dealt combat damage by one or more creatures you control, if that player lost less than 8 life this turn, they lose life equal to the difference."
public LolthSpiderQueenEmblem() {
super("Emblem Lolth");
- this.getAbilities().add(new ConditionalInterveningIfTriggeredAbility(
- new OneOrMoreCombatDamagePlayerTriggeredAbility(
- Zone.COMMAND, new LolthSpiderQueenEmblemEffect(), StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.PLAYER, false
- ), LolthSpiderQueenEmblemCondition.instance, "Whenever an opponent " +
- "is dealt combat damage by one or more creatures you control, " +
- "if that player lost less than 8 life this turn, they lose life equal to the difference."
- ));
+ this.getAbilities().add(new OneOrMoreCombatDamagePlayerTriggeredAbility(
+ Zone.COMMAND, new LolthSpiderQueenEmblemEffect(), StaticFilters.FILTER_PERMANENT_CREATURES, SetTargetPointer.PLAYER, false
+ ).withInterveningIf(LolthSpiderQueenEmblemCondition.instance).setTriggerPhrase("Whenever an opponent is dealt combat damage by one or more creatures you control, "));
}
private LolthSpiderQueenEmblem(final LolthSpiderQueenEmblem card) {
@@ -61,12 +56,18 @@ enum LolthSpiderQueenEmblemCondition implements Condition {
PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class);
return player != null && watcher != null && watcher.getLifeLost(player.getId()) < 8;
}
+
+ @Override
+ public String toString() {
+ return "that player lost less than 8 life this turn";
+ }
}
class LolthSpiderQueenEmblemEffect extends OneShotEffect {
LolthSpiderQueenEmblemEffect() {
super(Outcome.Benefit);
+ staticText = "they lose life equal to the difference";
}
private LolthSpiderQueenEmblemEffect(final LolthSpiderQueenEmblemEffect effect) {
diff --git a/Mage/src/main/java/mage/game/command/emblems/RadiationEmblem.java b/Mage/src/main/java/mage/game/command/emblems/RadiationEmblem.java
index 9c2fcd54a1a..7f72bf4b36c 100644
--- a/Mage/src/main/java/mage/game/command/emblems/RadiationEmblem.java
+++ b/Mage/src/main/java/mage/game/command/emblems/RadiationEmblem.java
@@ -1,10 +1,9 @@
package mage.game.command.emblems;
import mage.abilities.Ability;
-import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
import mage.abilities.condition.Condition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
+import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
import mage.cards.Cards;
import mage.cards.FrameStyle;
import mage.cards.repository.TokenInfo;
@@ -31,12 +30,9 @@ public class RadiationEmblem extends Emblem {
super("Radiation");
this.frameStyle = FrameStyle.M15_NORMAL;
- this.getAbilities().add(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfFirstMainTriggeredAbility(Zone.ALL, TargetController.YOU, new RadiationEffect(), false),
- RadiationCondition.instance,
- "At the beginning of your precombat main phase, if you have any rad counters, "
- + "mill that many cards. For each nonland card milled this way, you lose 1 life and a rad counter."
- ));
+ this.getAbilities().add(new BeginningOfFirstMainTriggeredAbility(
+ Zone.ALL, TargetController.YOU, new RadiationEffect(), false
+ ).withInterveningIf(RadiationCondition.instance).setTriggerPhrase("At the beginning of each player's precombat main phase, "));
TokenInfo foundInfo = TokenRepository.instance.findPreferredTokenInfoForXmage(TokenRepository.XMAGE_IMAGE_NAME_RADIATION, null);
if (foundInfo != null) {
@@ -69,6 +65,11 @@ enum RadiationCondition implements Condition {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.getCountersCount(CounterType.RAD) > 0;
}
+
+ @Override
+ public String toString() {
+ return "that player has one or more rad counters";
+ }
}
/**
diff --git a/Mage/src/main/java/mage/game/permanent/token/AshiokWickedManipulatorNightmareToken.java b/Mage/src/main/java/mage/game/permanent/token/AshiokWickedManipulatorNightmareToken.java
index 4e2812f731c..afa3fcf91cd 100644
--- a/Mage/src/main/java/mage/game/permanent/token/AshiokWickedManipulatorNightmareToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/AshiokWickedManipulatorNightmareToken.java
@@ -1,12 +1,11 @@
package mage.game.permanent.token;
import mage.MageInt;
-import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.abilities.condition.common.WasCardExiledThisTurnCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
+import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
@@ -22,21 +21,16 @@ public final class AshiokWickedManipulatorNightmareToken extends TokenImpl {
* /!\ You need to add CardsExiledThisTurnWatcher to any card using this token
*/
public AshiokWickedManipulatorNightmareToken() {
- super("Nightmare Token", "1/1 black Nightmare creature tokens with \"At the beginning of combat on your turn, if a card was put into exile this turn, put a +1/+1 counter on this creature.\"");
+ super("Nightmare Token", "1/1 black Nightmare creature token with \"At the beginning of combat on your turn, if a card was put into exile this turn, put a +1/+1 counter on this token.\"");
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add(SubType.NIGHTMARE);
power = new MageInt(1);
toughness = new MageInt(1);
- this.addAbility(new ConditionalInterveningIfTriggeredAbility(
- new BeginningOfCombatTriggeredAbility(
- new AddCountersSourceEffect(CounterType.P1P1.createInstance())
- ),
- WasCardExiledThisTurnCondition.instance,
- "At the beginning of combat on your turn, if a card was put into exile "
- + "this turn, put a +1/+1 counter on this creature."
- ).addHint(hint));
+ this.addAbility(new BeginningOfCombatTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance())
+ ).withInterveningIf(WasCardExiledThisTurnCondition.instance).addHint(hint));
}
private AshiokWickedManipulatorNightmareToken(final AshiokWickedManipulatorNightmareToken token) {
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 7bd07279026..b5e4f4fe03d 100644
--- a/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/BeastieToken.java
@@ -12,7 +12,7 @@ import mage.constants.SubType;
public final class BeastieToken extends TokenImpl {
public BeastieToken() {
- super("Beast Token", "4/4 white Beast creature token with \"This creature can't attack or block alone.\"");
+ super("Beast Token", "4/4 white Beast creature token with \"This token can't attack or block alone.\"");
cardType.add(CardType.CREATURE);
color.setWhite(true);
subtype.add(SubType.BEAST);
diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonMenaceAndStealArtifactToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonMenaceAndStealArtifactToken.java
index 09906bdad14..6b47dd7b914 100644
--- a/Mage/src/main/java/mage/game/permanent/token/DragonMenaceAndStealArtifactToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/DragonMenaceAndStealArtifactToken.java
@@ -11,7 +11,7 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactPermanent;
import mage.target.TargetPermanent;
-import mage.target.targetadjustment.DamagedPlayerControlsTargetAdjuster;
+import mage.target.targetadjustment.ThatPlayerControlsTargetAdjuster;
public class DragonMenaceAndStealArtifactToken extends TokenImpl {
@@ -31,7 +31,7 @@ public class DragonMenaceAndStealArtifactToken extends TokenImpl {
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new GainControlTargetEffect(Duration.EndOfGame), false, true);
ability.addTarget(new TargetPermanent(filter));
- ability.setTargetAdjuster(new DamagedPlayerControlsTargetAdjuster());
+ ability.setTargetAdjuster(new ThatPlayerControlsTargetAdjuster());
addAbility(ability);
}
diff --git a/Mage/src/main/java/mage/game/permanent/token/FishToken.java b/Mage/src/main/java/mage/game/permanent/token/FishToken.java
index 89c2170c151..38b409c0851 100644
--- a/Mage/src/main/java/mage/game/permanent/token/FishToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/FishToken.java
@@ -11,14 +11,14 @@ import mage.constants.SubType;
public final class FishToken extends TokenImpl {
public FishToken() {
- super("Fish Token", "1/1 blue Fish creature token with \"This creature can't be blocked.\"");
+ super("Fish Token", "1/1 blue Fish creature token with \"This token can't be blocked.\"");
cardType.add(CardType.CREATURE);
subtype.add(SubType.FISH);
color.setBlue(true);
power = new MageInt(1);
toughness = new MageInt(1);
- addAbility(new CantBeBlockedSourceAbility("this creature can't be blocked"));
+ addAbility(new CantBeBlockedSourceAbility("this token can't be blocked"));
}
private FishToken(final FishToken token) {
diff --git a/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java b/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java
index 87b3014c61d..6a73f0fba05 100644
--- a/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java
@@ -18,7 +18,7 @@ public final class GarrukCursedHuntsmanToken extends TokenImpl {
= new FilterControlledPermanent(SubType.GARRUK, "Garruk you control");
public GarrukCursedHuntsmanToken() {
- super("Wolf Token", "2/2 black and green Wolf creature token with \"When this creature dies, put a loyalty counter on each Garruk you control.\"");
+ super("Wolf Token", "2/2 black and green Wolf creature token with \"When this token dies, put a loyalty counter on each Garruk you control.\"");
cardType.add(CardType.CREATURE);
color.setBlack(true);
color.setGreen(true);
diff --git a/Mage/src/main/java/mage/game/permanent/token/Mutant33DeathtouchToken.java b/Mage/src/main/java/mage/game/permanent/token/Mutant33DeathtouchToken.java
new file mode 100644
index 00000000000..bfd77473771
--- /dev/null
+++ b/Mage/src/main/java/mage/game/permanent/token/Mutant33DeathtouchToken.java
@@ -0,0 +1,34 @@
+package mage.game.permanent.token;
+
+import mage.MageInt;
+import mage.abilities.keyword.DeathtouchAbility;
+import mage.constants.CardType;
+import mage.constants.SubType;
+
+/**
+ * @author padfoothelix
+ */
+
+
+public final class Mutant33DeathtouchToken extends TokenImpl {
+
+ public Mutant33DeathtouchToken() {
+ super("Mutant Token", "3/3 green mutant creature token with deathtouch");
+ cardType.add(CardType.CREATURE);
+ subtype.add(SubType.MUTANT);
+ color.setGreen(true);
+ power = new MageInt(3);
+ toughness = new MageInt(3);
+
+ addAbility(DeathtouchAbility.getInstance());
+ }
+
+ private Mutant33DeathtouchToken(final Mutant33DeathtouchToken token) {
+ super(token);
+ }
+
+ public Mutant33DeathtouchToken copy() {
+ return new Mutant33DeathtouchToken(this);
+ }
+}
+
diff --git a/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java b/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java
index 1ab3238b88e..93833f09d98 100644
--- a/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java
@@ -12,7 +12,7 @@ import mage.constants.SubType;
public final class Pest11GainLifeToken extends TokenImpl {
public Pest11GainLifeToken() {
- super("Pest Token", "1/1 black and green Pest creature token with \"When this creature dies, you gain 1 life.\"");
+ super("Pest Token", "1/1 black and green Pest creature token with \"When this token dies, you gain 1 life.\"");
cardType.add(CardType.CREATURE);
color.setBlack(true);
color.setGreen(true);
diff --git a/Mage/src/main/java/mage/game/permanent/token/PilotCrewToken.java b/Mage/src/main/java/mage/game/permanent/token/PilotCrewToken.java
index 4955c7c6d84..59c49d79df7 100644
--- a/Mage/src/main/java/mage/game/permanent/token/PilotCrewToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/PilotCrewToken.java
@@ -11,7 +11,7 @@ import mage.constants.SubType;
public final class PilotCrewToken extends TokenImpl {
public PilotCrewToken() {
- super("Pilot Token", "1/1 colorless Pilot creature token with \"This creature crews Vehicles as though its power were 2 greater.\"");
+ super("Pilot Token", "1/1 colorless Pilot creature token with \"This token crews Vehicles as though its power were 2 greater.\"");
cardType.add(CardType.CREATURE);
subtype.add(SubType.PILOT);
power = new MageInt(1);
diff --git a/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java
index 908e4c7f8f2..00b0721fc7c 100644
--- a/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java
@@ -22,7 +22,7 @@ public final class SeizeTheStormElementalToken extends TokenImpl {
public SeizeTheStormElementalToken(DynamicValue xValue, Hint hint) {
super("Elemental Token", "red Elemental creature token with trample and " +
- "\"This creature's power and toughness are each equal to the number of instant " +
+ "\"This token's power and toughness are each equal to the number of instant " +
"and sorcery cards in your graveyard plus the number of cards with flashback you own in exile.\"");
cardType.add(CardType.CREATURE);
color.setRed(true);
@@ -32,7 +32,7 @@ public final class SeizeTheStormElementalToken extends TokenImpl {
this.addAbility(TrampleAbility.getInstance());
this.addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(
xValue
- ).setText("this creature's power and toughness are each equal to the number of " +
+ ).setText("this token's power and toughness are each equal to the number of " +
"instant and sorcery cards in your graveyard, plus the number of cards with flashback you own in exile")
).addHint(hint));
}
diff --git a/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java b/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java
index 5925705fc98..c7d1f8932d0 100644
--- a/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/VrenRatToken.java
@@ -2,12 +2,13 @@ package mage.game.permanent.token;
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.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
-import mage.constants.Zone;
+import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
@@ -16,26 +17,23 @@ import mage.filter.predicate.mageobject.AnotherPredicate;
*/
public final class VrenRatToken extends TokenImpl {
- private static final FilterControlledPermanent filter = new FilterControlledPermanent("other Rat you control");
+ private static final FilterPermanent filter = new FilterControlledPermanent(SubType.RAT, "other Rat you control");
static {
- filter.add(SubType.RAT.getPredicate());
filter.add(AnotherPredicate.instance);
}
+ private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
+
public VrenRatToken() {
- super("Rat Token", "1/1 black Rat creature tokens with \"This creature gets +1/+1 for each other Rat you control\"");
+ super("Rat Token", "1/1 black Rat creature token with \"This token gets +1/+1 for each other Rat you control.\"");
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add(SubType.RAT);
power = new MageInt(1);
toughness = new MageInt(1);
- this.addAbility(new SimpleStaticAbility(
- new BoostSourceEffect(new PermanentsOnBattlefieldCount(filter),
- new PermanentsOnBattlefieldCount(filter), Duration.WhileOnBattlefield
- )
- ));
+ this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield)));
}
private VrenRatToken(final VrenRatToken token) {
diff --git a/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java b/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java
index a25f5aaa8c7..ac2080ca59a 100644
--- a/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java
@@ -15,7 +15,7 @@ import mage.constants.Zone;
public final class WrennAndSevenTreefolkToken extends TokenImpl {
public WrennAndSevenTreefolkToken() {
- super("Treefolk Token", "green Treefolk creature token with reach and \"This creature's power and toughness are each equal to the number of lands you control.\"");
+ super("Treefolk Token", "green Treefolk creature token with reach and \"This token's power and toughness are each equal to the number of lands you control.\"");
cardType.add(CardType.CREATURE);
color.setGreen(true);
subtype.add(SubType.TREEFOLK);
@@ -24,7 +24,7 @@ public final class WrennAndSevenTreefolkToken extends TokenImpl {
this.addAbility(ReachAbility.getInstance());
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(
LandsYouControlCount.instance
- ).setText("this creature's power and toughness are each equal to the number of lands you control")));
+ ).setText("this token's power and toughness are each equal to the number of lands you control")));
}
private WrennAndSevenTreefolkToken(final WrennAndSevenTreefolkToken token) {
diff --git a/Mage/src/main/java/mage/game/permanent/token/YoungHeroRoleToken.java b/Mage/src/main/java/mage/game/permanent/token/YoungHeroRoleToken.java
index d73aaf07a81..04eeb1a0090 100644
--- a/Mage/src/main/java/mage/game/permanent/token/YoungHeroRoleToken.java
+++ b/Mage/src/main/java/mage/game/permanent/token/YoungHeroRoleToken.java
@@ -5,7 +5,6 @@ import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceMatchesFilterCondition;
-import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
@@ -23,7 +22,7 @@ import mage.target.common.TargetCreaturePermanent;
*/
public final class YoungHeroRoleToken extends TokenImpl {
- private static final FilterPermanent filter = new FilterCreaturePermanent();
+ private static final FilterPermanent filter = new FilterCreaturePermanent("its toughness is 3 or less");
static {
filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 4));
@@ -45,10 +44,10 @@ public final class YoungHeroRoleToken extends TokenImpl {
// Enchanted creature has "Whenever this creature attacks, if its toughness is 3 or less, put a +1/+1 counter on it."
this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(
- new ConditionalInterveningIfTriggeredAbility(
- new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())),
- condition, "Whenever this creature attacks, if its toughness is 3 or less, put a +1/+1 counter on it."
- ), AttachmentType.AURA
+ new AttacksTriggeredAbility(
+ new AddCountersSourceEffect(CounterType.P1P1.createInstance())
+ .setText("put a +1/+1 counter on it")
+ ).withInterveningIf(condition), AttachmentType.AURA
)));
}
diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java
index a880c666afa..f83a90a5697 100644
--- a/Mage/src/main/java/mage/game/stack/StackAbility.java
+++ b/Mage/src/main/java/mage/game/stack/StackAbility.java
@@ -673,6 +673,10 @@ public class StackAbility extends StackObjectImpl implements Ability {
ability.setSourceObjectZoneChangeCounter(zoneChangeCounter);
}
+ @Override
+ public void initSourceObjectZoneChangeCounter(Game game, boolean force) {
+ ability.initSourceObjectZoneChangeCounter(game, force);
+ }
@Override
public int getSourceObjectZoneChangeCounter() {
return ability.getSourceObjectZoneChangeCounter();
diff --git a/Mage/src/main/java/mage/game/turn/PreCombatMainStep.java b/Mage/src/main/java/mage/game/turn/PreCombatMainStep.java
index 35d40f1d56e..4567c64731f 100644
--- a/Mage/src/main/java/mage/game/turn/PreCombatMainStep.java
+++ b/Mage/src/main/java/mage/game/turn/PreCombatMainStep.java
@@ -1,9 +1,11 @@
package mage.game.turn;
+import mage.abilities.common.SagaAbility;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
+import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
@@ -19,6 +21,7 @@ public class PreCombatMainStep extends Step {
static {
filter.add(SubType.SAGA.getPredicate());
+ filter.add(new AbilityPredicate(SagaAbility.class));
}
public PreCombatMainStep() {
diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java
index 14b9df75af5..1028d914a0c 100644
--- a/Mage/src/main/java/mage/players/Player.java
+++ b/Mage/src/main/java/mage/players/Player.java
@@ -784,12 +784,18 @@ public interface Player extends MageItem, Copyable {
* @return List of integers with size equal to messages.size(). The sum of the integers is equal to max.
*/
default List getMultiAmount(Outcome outcome, List messages, int optionMin, int totalMin, int totalMax, MultiAmountType type, Game game) {
+ // do not override it
+
+ // runtime check: make sure all default values are valid
+ // TODO: add default check inside getMultiAmountWithIndividualConstraints
if (optionMin > totalMax || optionMin * messages.size() > totalMin) {
throw new IllegalArgumentException(String.format("Wrong code usage: getMultiAmount found bad option min/max values: %d/%d", optionMin, totalMax));
}
+
List constraints = messages.stream()
.map(s -> new MultiAmountMessage(s, optionMin, totalMax))
.collect(Collectors.toList());
+
return getMultiAmountWithIndividualConstraints(outcome, constraints, totalMin, totalMax, type, game);
}
diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java
index 73ec0e6b91e..33227e25d36 100644
--- a/Mage/src/main/java/mage/players/PlayerImpl.java
+++ b/Mage/src/main/java/mage/players/PlayerImpl.java
@@ -1306,7 +1306,7 @@ public abstract class PlayerImpl implements Player, Serializable {
SpellAbility ability = originalAbility.copy();
Set allowedIdentifiers = originalAbility.spellCanBeActivatedNow(getId(), game);
ability.setControllerId(getId());
- ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId()));
+ ability.initSourceObjectZoneChangeCounter(game, true);
//20091005 - 601.2a
if (ability.getSourceId() == null) {
@@ -1332,7 +1332,7 @@ public abstract class PlayerImpl implements Player, Serializable {
spell.setCopy(true, null);
}
// Update the zcc to the stack
- ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId()));
+ ability.initSourceObjectZoneChangeCounter(game, true);
// ALTERNATIVE COST from dynamic effects
// some effects set sourceId to cast without paying mana costs or other costs
@@ -3088,7 +3088,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (winnable) {
game.informPlayers(getLogName() + " won the flip" + CardUtil.getSourceLogName(game, source));
}
- game.fireEvent(new FlipCoinEvent(playerId, source, true, true, winnable).createFlippedEvent());
+ game.fireEvent(new FlipCoinEvent(playerId, source, true, true, true).createFlippedEvent());
results.add(true);
continue;
}
diff --git a/Mage/src/main/java/mage/target/TargetCard.java b/Mage/src/main/java/mage/target/TargetCard.java
index e0ef2ba5bfe..118ca88ed9e 100644
--- a/Mage/src/main/java/mage/target/TargetCard.java
+++ b/Mage/src/main/java/mage/target/TargetCard.java
@@ -180,7 +180,7 @@ public class TargetCard extends TargetObject {
int possibleTargets = 0;
for (Card card : game.getExile().getPermanentExile().getCards(game)) {
if (sourceId == null || isNotTarget || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) {
- if (filter.match(card, player.getId(), game)) {
+ if (filter.match(card, player.getId(), source, game)) {
possibleTargets++;
if (possibleTargets >= countUpTo) {
return possibleTargets; // early return for faster computation.
@@ -216,7 +216,7 @@ public class TargetCard extends TargetObject {
@Override
public Set possibleTargets(UUID sourceControllerId, Game game) {
- return possibleTargets(sourceControllerId, (Ability) null, game);
+ return possibleTargets(sourceControllerId, null, game);
}
public Set possibleTargets(UUID sourceControllerId, Cards cards, Ability source, Game game) {
diff --git a/Mage/src/main/java/mage/target/common/TargetCardInExile.java b/Mage/src/main/java/mage/target/common/TargetCardInExile.java
index 50a71d6636b..2c8cba1d09a 100644
--- a/Mage/src/main/java/mage/target/common/TargetCardInExile.java
+++ b/Mage/src/main/java/mage/target/common/TargetCardInExile.java
@@ -75,7 +75,7 @@ public class TargetCardInExile extends TargetCard {
ExileZone exileZone = game.getExile().getExileZone(zoneId);
if (exileZone != null) {
for (Card card : exileZone.getCards(game)) {
- if (filter.match(card, sourceControllerId, game)) {
+ if (filter.match(card, sourceControllerId, source, game)) {
possibleTargets.add(card.getId());
}
}
@@ -96,11 +96,8 @@ public class TargetCardInExile extends TargetCard {
}
} else {
ExileZone exileZone = game.getExile().getExileZone(zoneId);
- if (exileZone != null) {
- if (exileZone.count(filter, sourceControllerId, source, game) >= this.minNumberOfTargets) {
- return true;
- }
- }
+ return exileZone != null && exileZone.count(filter, sourceControllerId, source, game) >= this.minNumberOfTargets;
+
}
return false;
}
diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java
index a508ead9533..6a8ffe544b7 100644
--- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java
+++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalkerAmount.java
@@ -1,6 +1,5 @@
package mage.target.common;
-import mage.filter.common.FilterControlledCreatureOrPlaneswalkerPermanent;
import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent;
/**
@@ -53,22 +52,6 @@ public class TargetCreatureOrPlaneswalkerAmount extends TargetPermanentAmount {
super(amount, minNumberOfTargets, maxNumberOfTargets, filter);
}
- /**
- * IMPORTANT: Use more specific constructor if {@code amount} is not always the same number!
- *
- * @see TargetCreatureOrPlaneswalkerAmount#TargetCreatureOrPlaneswalkerAmount(int, FilterCreatureOrPlaneswalkerPermanent)
- */
- public TargetCreatureOrPlaneswalkerAmount(int amount, FilterControlledCreatureOrPlaneswalkerPermanent filter) {
- this(amount, amount > 3 ? 0 : 1, amount, filter);
- }
-
- /**
- * @see TargetCreatureOrPlaneswalkerAmount#TargetCreatureOrPlaneswalkerAmount(int, int, int, FilterCreatureOrPlaneswalkerPermanent)
- */
- public TargetCreatureOrPlaneswalkerAmount(int amount, int minNumberOfTargets, int maxNumberOfTargets, FilterControlledCreatureOrPlaneswalkerPermanent filter) {
- super(amount, minNumberOfTargets, maxNumberOfTargets, filter);
- }
-
private TargetCreatureOrPlaneswalkerAmount(final TargetCreatureOrPlaneswalkerAmount target) {
super(target);
}
diff --git a/Mage/src/main/java/mage/target/common/TargetDiscard.java b/Mage/src/main/java/mage/target/common/TargetDiscard.java
index 854230c9eaf..4e732d8ba09 100644
--- a/Mage/src/main/java/mage/target/common/TargetDiscard.java
+++ b/Mage/src/main/java/mage/target/common/TargetDiscard.java
@@ -47,7 +47,7 @@ public class TargetDiscard extends TargetCard {
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
Card card = game.getPlayer(playerId).getHand().get(id, game);
- return filter.match(card, source.getControllerId(), game);
+ return filter.match(card, source.getControllerId(), source, game);
}
@Override
diff --git a/Mage/src/main/java/mage/target/targetadjustment/DamagedPlayerControlsTargetAdjuster.java b/Mage/src/main/java/mage/target/targetadjustment/ThatPlayerControlsTargetAdjuster.java
similarity index 80%
rename from Mage/src/main/java/mage/target/targetadjustment/DamagedPlayerControlsTargetAdjuster.java
rename to Mage/src/main/java/mage/target/targetadjustment/ThatPlayerControlsTargetAdjuster.java
index 73694ca6d41..eacea107664 100644
--- a/Mage/src/main/java/mage/target/targetadjustment/DamagedPlayerControlsTargetAdjuster.java
+++ b/Mage/src/main/java/mage/target/targetadjustment/ThatPlayerControlsTargetAdjuster.java
@@ -1,7 +1,6 @@
package mage.target.targetadjustment;
import mage.abilities.Ability;
-import mage.abilities.common.OneOrMoreDamagePlayerTriggeredAbility;
import mage.filter.Filter;
import mage.filter.predicate.card.OwnerIdPredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
@@ -17,20 +16,20 @@ import java.util.UUID;
/**
* @author notgreat
*/
-public class DamagedPlayerControlsTargetAdjuster extends GenericTargetAdjuster {
+public class ThatPlayerControlsTargetAdjuster extends GenericTargetAdjuster {
private final boolean owner;
/**
* Use with {@link mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility} with setTargetPointer enabled,
- * or {@link OneOrMoreDamagePlayerTriggeredAbility} with "SetTargetPointer.PLAYER" or similar.
- * Adjusts the target to only target something the damaged player controls (or owns with alternative constructor)
- * And then removes the effects' target pointer that the triggered ability set
+ * or {@link mage.abilities.common.OneOrMoreDamagePlayerTriggeredAbility} with "SetTargetPointer.PLAYER" or similar.
+ * Adjusts the target to only target something the damaged/attacked/etc. player controls (or owns with alternative constructor)
+ * And then removes the effects' target pointer that the triggered ability set, replacing it with the standard {@link FirstTargetPointer}
*/
- public DamagedPlayerControlsTargetAdjuster() {
+ public ThatPlayerControlsTargetAdjuster() {
this(false);
}
- public DamagedPlayerControlsTargetAdjuster(boolean owner) {
+ public ThatPlayerControlsTargetAdjuster(boolean owner) {
this.owner = owner;
}
diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java
index f1073e32c4c..8cd26e37641 100644
--- a/Mage/src/main/java/mage/util/CardUtil.java
+++ b/Mage/src/main/java/mage/util/CardUtil.java
@@ -85,7 +85,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", "sacrifice", "remove", "tap", "reveal", "pay", "collect"
+ "put", "return", "exile", "discard", "sacrifice", "remove", "tap", "reveal", "pay", "collect", "forage"
);
// search set code in commands like "set_code-card_name"
@@ -980,7 +980,7 @@ public final class CardUtil {
}
if (!targetPlayerGets) {
sb.append(add ? " on " : " from ");
- if (description.contains("up to")) {
+ if (description.contains("up to") && !description.contains("up to one")) {
sb.append("each of ");
}
sb.append(description);
@@ -1774,8 +1774,9 @@ public final class CardUtil {
// Waiting on actual ruling of Ashiok, Wicked Manipulator.
return true;
}
- if (player.loseLife(lifeToPay, game, source, false) >= lifeToPay) {
- game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIFE_PAID, player.getId(), source, player.getId(), lifeToPay));
+ int lostLife = player.loseLife(lifeToPay, game, source, false);
+ if (lostLife > 0) {
+ game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIFE_PAID, player.getId(), source, player.getId(), lostLife));
return true;
}
diff --git a/Mage/src/main/java/mage/util/MultiAmountMessage.java b/Mage/src/main/java/mage/util/MultiAmountMessage.java
index 3749c20c408..ce4f72f98a9 100644
--- a/Mage/src/main/java/mage/util/MultiAmountMessage.java
+++ b/Mage/src/main/java/mage/util/MultiAmountMessage.java
@@ -5,9 +5,10 @@ import java.io.Serializable;
/**
* A helper class for facilitating the multi-choose dialog
*
- * @author alexander-novo
+ * @author alexander-novo, JayDi85
*/
-public class MultiAmountMessage implements Serializable {
+public class MultiAmountMessage implements Serializable, Copyable {
+
public String message;
public int min;
public int max;
@@ -24,8 +25,20 @@ public class MultiAmountMessage implements Serializable {
this.defaultValue = defaultValue;
}
+ private MultiAmountMessage(final MultiAmountMessage mes) {
+ this.message = mes.message;
+ this.min = mes.min;
+ this.max = mes.max;
+ this.defaultValue = mes.defaultValue;
+ }
+
@Override
public String toString() {
return String.format("%s - from %d to %d - default %d", message, min, max, defaultValue);
}
+
+ @Override
+ public MultiAmountMessage copy() {
+ return new MultiAmountMessage(this);
+ }
}
diff --git a/Mage/src/main/java/mage/watchers/common/DealtDamageThisGameWatcher.java b/Mage/src/main/java/mage/watchers/common/DealtDamageThisGameWatcher.java
new file mode 100644
index 00000000000..a537a64c7b5
--- /dev/null
+++ b/Mage/src/main/java/mage/watchers/common/DealtDamageThisGameWatcher.java
@@ -0,0 +1,52 @@
+package mage.watchers.common;
+
+import mage.MageObjectReference;
+import mage.abilities.Ability;
+import mage.constants.WatcherScope;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+import mage.watchers.Watcher;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author TheElk801
+ */
+public class DealtDamageThisGameWatcher extends Watcher {
+
+ private final Set damagers = new HashSet<>();
+
+ public DealtDamageThisGameWatcher() {
+ super(WatcherScope.GAME);
+ }
+
+ @Override
+ public void watch(GameEvent event, Game game) {
+ switch (event.getType()) {
+ case BEGINNING_PHASE_PRE:
+ // keep the stored values from getting too big, especially since it doesn't reset between games
+ damagers.removeIf(mor -> !mor.zoneCounterIsCurrent(game));
+ return;
+ case DAMAGED_PERMANENT:
+ case DAMAGED_PLAYER:
+ break;
+ default:
+ return;
+ }
+ Permanent permanent = game.getPermanent(event.getSourceId());
+ if (permanent != null) {
+ damagers.add(new MageObjectReference(permanent, game));
+ }
+ }
+
+ public static boolean checkCreature(Game game, Ability source) {
+ return game
+ .getState()
+ .getWatcher(DealtDamageThisGameWatcher.class)
+ .damagers
+ .stream()
+ .noneMatch(mor -> mor.refersTo(source.getSourcePermanentOrLKI(game), game));
+ }
+}
diff --git a/Mage/src/main/resources/brackets/infinite-combos.txt b/Mage/src/main/resources/brackets/infinite-combos.txt
new file mode 100644
index 00000000000..534ba1e1e05
--- /dev/null
+++ b/Mage/src/main/resources/brackets/infinite-combos.txt
@@ -0,0 +1,1994 @@
+# Infinite x2 cards combos list for Commander Brackets calculation
+# Format: name1@name2 - any order, any card names, can duplicates
+# Generated by verify test VerifyCardDataTest.downloadAndPrepareCommanderBracketsData
+# Source: https://commanderspellbook.com
+# Updated: 2025-06-06
+# Found: 1988
+Bloodchief Ascension@Mindcrank
+Zaxara, the Exemplary@Freed from the Real
+Brallin, Skyshark Rider@Ophidian Eye
+Krosan Restorer@Ashaya, Soul of the Wild
+Animar, Soul of Elements@Ancestral Statue
+Leonin Relic-Warder@Animate Dead
+Hapatra, Vizier of Poisons@Blowfly Infestation
+Tooth and Claw@Primal Vigor
+Twincast@Reverberate
+Stormfront Riders@Cryptic Gateway
+Molten Echoes@Felidar Guardian
+Palinchron@Flameshadow Conjuring
+Painter's Servant@Grindstone
+Intruder Alarm@Krenko, Mob Boss
+Conspiracy@Turntimber Ranger
+Opalescence@Parallax Wave
+Erratic Portal@Emrakul, the Aeons Torn
+Pili-Pala@Grand Architect
+Freed from the Real@Ley Weaver
+Faeburrow Elder@Freed from the Real
+Vraska, Swarm's Eminence@Walking Ballista
+Staff of Domination@Selvala, Heart of the Wilds
+Molten Echoes@Wispweaver Angel
+Devoted Druid@One with the Stars
+Dramatic Reversal@Isochron Scepter
+Peregrine Drake@Deadeye Navigator
+Sekki, Seasons' Guide@Warstorm Surge
+Worldgorger Dragon@Molten Echoes
+Niv-Mizzet, the Firemind@Tandem Lookout
+The Locust God@Sage of the Falls
+Glint-Horn Buccaneer@Ophidian Eye
+Godo, Bandit Warlord@Helm of the Host
+Muldrotha, the Gravetide@Second Chance
+Boros Reckoner@Avacyn, Angel of Hope
+Venser, Shaper Savant@Intruder Alarm
+The Locust God@Beck // Call
+Nekusar, the Mindrazer@Peer into the Abyss
+Temple Bell@Mind Over Matter
+Guile@Void Mirror
+Famished Paladin@Sorcerer's Wand
+Mephidross Vampire@Walking Ballista
+Panoptic Mirror@Time Warp
+Thousand-Year Storm@Spelljack
+Intruder Alarm@Whitemane Lion
+Grumgully, the Generous@Aerie Ouphes
+Goblin Sharpshooter@Splinter Twin
+Animate Dead@Worldgorger Dragon
+Seedcradle Witch@Wirewood Channeler
+Mephidross Vampire@Triskelion
+Great Whale@Deadeye Navigator
+Guile@Cephalid Shrine
+Molten Echoes@Wanderwine Prophets
+Scourge of the Skyclaves@Archfiend of Despair
+Cryptic Trilobite@Enduring Renewal
+Walking Ballista@Mikaeus, the Unhallowed
+Stonecoil Serpent@Enduring Renewal
+Bladewing the Risen@Heat Shimmer
+Archon of Sun's Grace@Enchanted Evening
+Leonin Relic-Warder@Phyrexian Metamorph
+Necrotic Ooze@Kiki-Jiki, Mirror Breaker
+Aminatou, the Fateshifter@Felidar Guardian
+Azami, Lady of Scrolls@Mind Over Matter
+Reset@Reiterate
+Dockside Extortionist@Barrin, Master Wizard
+Sea Gate Loremaster@Mind Over Matter
+Spawnsire of Ulamog@Training Grounds
+Aggravated Assault@Nature's Will
+Kiki-Jiki, Mirror Breaker@Deceiver Exarch
+Kiki-Jiki, Mirror Breaker@Trumpeting Gnarr
+Walking Ballista@Enduring Renewal
+Kiki-Jiki, Mirror Breaker@Hyrax Tower Scout
+Basalt Monolith@Forsaken Monument
+Rakdos, Lord of Riots@Ancestral Statue
+Hangarback Walker@Enduring Renewal
+Charmbreaker Devils@Time Warp
+Ral, Storm Conduit@Chain of Smog
+Leonin Relic-Warder@Dance of the Dead
+Naru Meha, Master Wizard@Sublime Epiphany
+Dockside Extortionist@Temur Sabertooth
+Kiki-Jiki, Mirror Breaker@Dirge Bat
+Brallin, Skyshark Rider@Curiosity
+Ilharg, the Raze-Boar@Medomai the Ageless
+Intruder Alarm@Drana's Chosen
+Filigree Sages@Chromatic Orrery
+Palinchron@Caged Sun
+Combat Celebrant@Splinter Twin
+Jolrael, Empress of Beasts@Aggravated Assault
+Saheeli Rai@Felidar Guardian
+Zaxara, the Exemplary@Pemmin's Aura
+Dualcaster Mage@Release to the Wind
+Heliod, Sun-Crowned@Walking Ballista
+Splinter Twin@Zealous Conscripts
+Leonin Relic-Warder@Mycosynth Lattice
+Neheb, Dreadhorde Champion@Aggravated Assault
+Nivix Guildmage@Brass's Bounty
+Pemmin's Aura@Krosan Restorer
+Aluren@Cloudstone Curio
+Brallin, Skyshark Rider@Keen Sense
+Mana Geyser@Reiterate
+Brudiclad, Telchor Engineer@Breath of Fury
+Mana Geyser@Reiterate
+Devoted Druid@One with the Stars
+Archon of Sun's Grace@Enchanted Evening
+Kiki-Jiki, Mirror Breaker@Trumpeting Gnarr
+Earthcraft@Spawning Grounds
+Aluren@Cloudstone Curio
+Scourge of the Skyclaves@Archfiend of Despair
+Twincast@Reverberate
+Cryptic Trilobite@Enduring Renewal
+Reality Spasm@Reiterate
+Walking Ballista@Mikaeus, the Unhallowed
+Sekki, Seasons' Guide@Warstorm Surge
+Basalt Monolith@Mesmeric Orb
+Spawnsire of Ulamog@Parallel Lives
+Seedcradle Witch@Wirewood Channeler
+Intruder Alarm@Whitemane Lion
+Wispweaver Angel@Felidar Guardian
+Faeburrow Elder@Freed from the Real
+Grumgully, the Generous@Aerie Ouphes
+Boros Reckoner@Avacyn, Angel of Hope
+Intruder Alarm@Krenko, Mob Boss
+Kiki-Jiki, Mirror Breaker@Deceiver Exarch
+Guile@Void Mirror
+Freed from the Real@Ley Weaver
+Kiki-Jiki, Mirror Breaker@Dirge Bat
+Niv-Mizzet, Parun@Ophidian Eye
+Walking Ballista@Enduring Renewal
+Reset@Reiterate
+Dockside Extortionist@Barrin, Master Wizard
+Heliod, Sun-Crowned@Walking Ballista
+Pemmin's Aura@Krosan Restorer
+Burnt Offering@Reiterate
+Opalescence@Parallax Wave
+Goblin Sharpshooter@Splinter Twin
+Hapatra, Vizier of Poisons@Blowfly Infestation
+Rakdos, Lord of Riots@Ancestral Statue
+Dramatic Reversal@Isochron Scepter
+Peregrine Drake@Deadeye Navigator
+Kiki-Jiki, Mirror Breaker@Hyrax Tower Scout
+Sydri, Galvanic Genius@Aetherflux Reservoir
+Chain of Acid@Ral, Storm Conduit
+Stonecoil Serpent@Enduring Renewal
+Leonin Relic-Warder@Animate Dead
+Conspiracy@Turntimber Ranger
+Spike Feeder@Sunbond
+Mephidross Vampire@Triskelion
+Dockside Extortionist@Temur Sabertooth
+Venser, Shaper Savant@Intruder Alarm
+Azami, Lady of Scrolls@Mind Over Matter
+Hangarback Walker@Enduring Renewal
+Charmbreaker Devils@Time Warp
+Molten Echoes@Wispweaver Angel
+Godo, Bandit Warlord@Helm of the Host
+Mephidross Vampire@Walking Ballista
+Leonin Relic-Warder@Dance of the Dead
+Animate Dead@Worldgorger Dragon
+Temple Bell@Mind Over Matter
+Naru Meha, Master Wizard@Sublime Epiphany
+Parallax Wave@Felidar Guardian
+Wakeroot Elemental@Growing Rites of Itlimoc // Itlimoc, Cradle of the Sun
+Zaxara, the Exemplary@Freed from the Real
+Hellkite Charger@Bear Umbra
+Brallin, Skyshark Rider@Curiosity
+Worldgorger Dragon@Molten Echoes
+Spawnsire of Ulamog@Training Grounds
+The Locust God@Sage of the Falls
+Intruder Alarm@Drana's Chosen
+Stormfront Riders@Cryptic Gateway
+Vraska, Swarm's Eminence@Walking Ballista
+Great Whale@Deadeye Navigator
+Thousand-Year Storm@Spelljack
+Filigree Sages@Chromatic Orrery
+Staff of Domination@Selvala, Heart of the Wilds
+Necrotic Ooze@Kiki-Jiki, Mirror Breaker
+Jolrael, Empress of Beasts@Aggravated Assault
+Muldrotha, the Gravetide@Second Chance
+Saheeli Rai@Felidar Guardian
+Famished Paladin@Sorcerer's Wand
+Lion's Eye Diamond@Auriok Salvagers
+Painter's Servant@Grindstone
+Dualcaster Mage@Release to the Wind
+Charmbreaker Devils@Time Walk
+Ceaseless Searblades@Lavaclaw Reaches
+Combat Celebrant@Splinter Twin
+Splinter Twin@Zealous Conscripts
+Bladewing the Risen@Heat Shimmer
+Basalt Monolith@Forsaken Monument
+Leonin Relic-Warder@Mycosynth Lattice
+Leonin Relic-Warder@Phyrexian Metamorph
+Neheb, Dreadhorde Champion@Aggravated Assault
+Nivix Guildmage@Brass's Bounty
+Molten Echoes@Wanderwine Prophets
+Aminatou, the Fateshifter@Felidar Guardian
+Ral, Storm Conduit@Chain of Smog
+Panoptic Mirror@Time Warp
+Reset@Izzet Guildmage
+Brallin, Skyshark Rider@Keen Sense
+Zaxara, the Exemplary@Pemmin's Aura
+Sea Gate Loremaster@Mind Over Matter
+Boros Reckoner@Gift of Doom
+Panoptic Mirror@Time Warp
+Niv-Mizzet, the Firemind@Tandem Lookout
+Mana Geyser@Reiterate
+Palinchron@Flameshadow Conjuring
+Guile@Void Mirror
+Freed from the Real@Gyre Engineer
+Archon of Sun's Grace@Enchanted Evening
+Devoted Druid@One with the Stars
+Kiki-Jiki, Mirror Breaker@Trumpeting Gnarr
+Staff of Domination@Selvala, Heart of the Wilds
+Vraska, Swarm's Eminence@Triskelion
+Worldgorger Dragon@Molten Echoes
+Aggravated Assault@Nature's Will
+Aluren@Cloudstone Curio
+Scourge of the Skyclaves@Archfiend of Despair
+Tooth and Claw@Primal Vigor
+Sekki, Seasons' Guide@Warstorm Surge
+Endless One@Enduring Renewal
+Cryptic Trilobite@Enduring Renewal
+Boros Reckoner@Boros Charm
+Glarecaster@Volcano Hellion
+Spawnsire of Ulamog@Parallel Lives
+Walking Ballista@Mikaeus, the Unhallowed
+Seeker of Skybreak@Wake Thrasher
+Grumgully, the Generous@Aerie Ouphes
+Dramatic Reversal@Isochron Scepter
+Grim Monolith@Mana Reflection
+Wakeroot Elemental@Growing Rites of Itlimoc // Itlimoc, Cradle of the Sun
+Ral, Storm Conduit@Chain of Smog
+Soulfire Grand Master@Temporal Manipulation
+Aminatou, the Fateshifter@Felidar Guardian
+Molten Echoes@Wanderwine Prophets
+Arixmethes, Slumbering Isle@Freed from the Real
+Basalt Monolith@Mana Reflection
+Enduring Renewal@Ashnod's Altar
+Lithoform Engine@Sands of Time
+Intruder Alarm@Krenko, Mob Boss
+Heliod, Sun-Crowned@Walking Ballista
+Hellkite Charger@Bear Umbra
+Shrieking Drake@Earthcraft
+Spawnsire of Ulamog@Training Grounds
+Molten Echoes@Felidar Guardian
+Boros Reckoner@Avacyn, Angel of Hope
+Freed from the Real@Argothian Elder
+Kiki-Jiki, Mirror Breaker@Deceiver Exarch
+The Locust God@Sage of the Falls
+Earthcraft@Spawning Grounds
+Freed from the Real@Ley Weaver
+Molten Echoes@Wispweaver Angel
+Muldrotha, the Gravetide@Second Chance
+Mephidross Vampire@Walking Ballista
+Charmbreaker Devils@Time Walk
+Timestream Navigator@Grenzo, Dungeon Warden
+Spawnsire of Ulamog@Illusionist's Bracers
+Walking Ballista@Enduring Renewal
+Scourge of the Skyclaves@Wound Reflection
+Reset@Reiterate
+Lion's Eye Diamond@Auriok Salvagers
+Dockside Extortionist@Barrin, Master Wizard
+Kiki-Jiki, Mirror Breaker@Cavern Whisperer
+Spike Feeder@Sunbond
+Krosan Restorer@Ashaya, Soul of the Wild
+Niv-Mizzet, Parun@Ophidian Eye
+Vizkopa Guildmage@Revival // Revenge
+Ceaseless Searblades@Lavaclaw Reaches
+Famished Paladin@Sorcerer's Wand
+Burnt Offering@Reiterate
+Seedcradle Witch@Wirewood Channeler
+Godo, Bandit Warlord@Helm of the Host
+Goblin Sharpshooter@Splinter Twin
+The Locust God@Beck // Call
+Kiki-Jiki, Mirror Breaker@Hyrax Tower Scout
+Zaxara, the Exemplary@Pemmin's Aura
+Rakdos, Lord of Riots@Ancestral Statue
+Nekusar, the Mindrazer@Peer into the Abyss
+Wakeroot Elemental@Nykthos, Shrine to Nyx
+Peregrine Drake@Deadeye Navigator
+Intruder Alarm@Whitemane Lion
+Naru Meha, Master Wizard@Ghostly Flicker
+Venser, Shaper Savant@Intruder Alarm
+Soulfire Grand Master@Walk the Aeons
+Stormfront Riders@Cryptic Gateway
+Soulfire Grand Master@Time Walk
+Tooth and Claw@Parallel Lives
+Stonecoil Serpent@Enduring Renewal
+Zaxara, the Exemplary@Freed from the Real
+Parallax Wave@Felidar Guardian
+Ley Weaver@Maze of Ith
+Faeburrow Elder@Freed from the Real
+Kiki-Jiki, Mirror Breaker@Wispweaver Angel
+Crackdown Construct@Chimeric Idol
+Kiki-Jiki, Mirror Breaker@Dirge Bat
+Mephidross Vampire@Triskelion
+Polyraptor@Forerunner of the Empire
+Dockside Extortionist@Temur Sabertooth
+Brudiclad, Telchor Engineer@Breath of Fury
+Brago, King Eternal@Strionic Resonator
+Palinchron@Nyxbloom Ancient
+Azami, Lady of Scrolls@Mind Over Matter
+Najeela, the Blade-Blossom@Derevi, Empyrial Tactician
+Hangarback Walker@Enduring Renewal
+Basalt Monolith@Nyxbloom Ancient
+Pemmin's Aura@Krosan Restorer
+Charmbreaker Devils@Time Warp
+Dualcaster Mage@Twinflame
+Basalt Monolith@Mesmeric Orb
+Raptor Hatchling@Warstorm Surge
+Animate Dead@Worldgorger Dragon
+Muldrotha, the Gravetide@Second Chance
+Naru Meha, Master Wizard@Ghostly Flicker
+Leonin Relic-Warder@Dance of the Dead
+Molten Echoes@Wispweaver Angel
+Heliod, Sun-Crowned@Walking Ballista
+Freed from the Real@Ley Weaver
+Temple Bell@Mind Over Matter
+Mesmeric Orb@Seeker of Skybreak
+The Locust God@Beck // Call
+Naru Meha, Master Wizard@Sublime Epiphany
+Boros Reckoner@Gift of Doom
+Nexus of Fate@Spellbinder
+Siona, Captain of the Pyleas@Shielded by Faith
+Sydri, Galvanic Genius@Aetherflux Reservoir
+Rings of Brighthearth@Basalt Monolith
+Brallin, Skyshark Rider@Tandem Lookout
+Tooth and Claw@Primal Vigor
+Bloodchief Ascension@Mindcrank
+Vraska, Swarm's Eminence@Walking Ballista
+Brallin, Skyshark Rider@Curiosity
+Burnt Offering@Reiterate
+Brudiclad, Telchor Engineer@Breath of Fury
+Arcanis the Omnipotent@Mind Over Matter
+Neheb, the Eternal@Aggravated Assault
+Parallax Wave@Felidar Guardian
+Reality Spasm@Reiterate
+Guile@Void Mirror
+Grumgully, the Generous@Aerie Ouphes
+Battered Golem@Splinter Twin
+Boros Reckoner@Indestructibility
+Inalla, Archmage Ritualist@Wanderwine Prophets
+Zaxara, the Exemplary@Freed from the Real
+Great Whale@Deadeye Navigator
+Animar, Soul of Elements@Ancestral Statue
+Thousand-Year Storm@Spelljack
+Molten Echoes@Wanderwine Prophets
+Filigree Sages@Chromatic Orrery
+Kiki-Jiki, Mirror Breaker@Wispweaver Angel
+Glint-Horn Buccaneer@Ophidian Eye
+Planar Portal@Nexus of Fate
+Famished Paladin@Sorcerer's Wand
+Necrotic Ooze@Kiki-Jiki, Mirror Breaker
+Jolrael, Empress of Beasts@Aggravated Assault
+Polyraptor@Forerunner of the Empire
+Kiki-Jiki, Mirror Breaker@Spark Double
+Gravecrawler@Phyrexian Altar
+Saheeli Rai@Felidar Guardian
+Faeburrow Elder@Freed from the Real
+Worldgorger Dragon@Molten Echoes
+Kiki-Jiki, Mirror Breaker@Breaching Hippocamp
+Maddening Cacophony@Bruvac the Grandiloquent
+Seedcradle Witch@Selvala, Heart of the Wilds
+Intruder Alarm@Kor Skyfisher
+Staff of Domination@Selvala, Heart of the Wilds
+Dualcaster Mage@Release to the Wind
+Lithoform Engine@Sands of Time
+Soulfire Grand Master@Capture of Jingzhou
+Zacama, Primal Calamity@Temur Sabertooth
+Charmbreaker Devils@Walk the Aeons
+Aetherflux Reservoir@March of the Machines
+Combat Celebrant@Splinter Twin
+Soulfire Grand Master@Temporal Manipulation
+Molten Echoes@Felidar Guardian
+Splinter Twin@Zealous Conscripts
+Bladewing the Risen@Heat Shimmer
+Stormfront Riders@Cryptic Gateway
+Basalt Monolith@Forsaken Monument
+Kiki-Jiki, Mirror Breaker@Timestream Navigator
+Leonin Relic-Warder@Mycosynth Lattice
+Reset@Nivix Guildmage
+Leonin Relic-Warder@Phyrexian Metamorph
+Nekusar, the Mindrazer@Peer into the Abyss
+Neheb, Dreadhorde Champion@Aggravated Assault
+Fury Storm@Ral, Storm Conduit
+Dramatic Reversal@Isochron Scepter
+Nivix Guildmage@Brass's Bounty
+Timestream Navigator@Grenzo, Dungeon Warden
+Conspiracy@Turntimber Ranger
+Intruder Alarm@Shrieking Drake
+Brallin, Skyshark Rider@Ophidian Eye
+Painter's Servant@Grindstone
+Niv-Mizzet, Parun@Ophidian Eye
+Mycosynth Golem@Ancestral Statue
+Wakeroot Elemental@Growing Rites of Itlimoc // Itlimoc, Cradle of the Sun
+Erratic Portal@Emrakul, the Aeons Torn
+Hapatra, Vizier of Poisons@Blowfly Infestation
+Intruder Alarm@Krenko, Mob Boss
+Mephidross Vampire@Walking Ballista
+Opalescence@Parallax Wave
+Palinchron@Flameshadow Conjuring
+Sea Gate Loremaster@Mind Over Matter
+Dance of the Dead@Worldgorger Dragon
+Zacama, Primal Calamity@Sanctum of Eternity
+Palinchron@Flameshadow Conjuring
+Panoptic Mirror@Time Warp
+Ilharg, the Raze-Boar@Medomai the Ageless
+Freed from the Real@Ley Weaver
+Hapatra, Vizier of Poisons@Blowfly Infestation
+Mana Geyser@Reiterate
+Faeburrow Elder@Freed from the Real
+Dockside Extortionist@Deadeye Navigator
+Twincast@Reverberate
+Chain of Acid@Ral, Storm Conduit
+Kiki-Jiki, Mirror Breaker@Sparring Mummy
+Najeela, the Blade-Blossom@Sword of Feast and Famine
+Najeela, the Blade-Blossom@Bear Umbra
+Sigil Tracer@Dramatic Reversal
+Meletis Charlatan@Dramatic Reversal
+Turnabout@Mirror Sheen
+Famished Paladin@Resplendent Mentor
+Cephalid Illusionist@Shuko
+Cephalid Illusionist@Lightning Greaves
+Lich@Repay in Kind
+Brago, King Eternal@Aurelia, the Warleader
+Naru Meha, Master Wizard@Displace
+Squee, the Immortal@Food Chain
+Eternal Scourge@Food Chain
+Filigree Sages@Doubling Cube
+Pitiless Plunderer@March of the Machines
+Pitiless Plunderer@Titania's Song
+Village Bell-Ringer@Temur Sabertooth
+Kiki-Jiki, Mirror Breaker@Aphetto Alchemist
+Kiki-Jiki, Mirror Breaker@Fatestitcher
+Kiki-Jiki, Mirror Breaker@Kiora's Follower
+Kiki-Jiki, Mirror Breaker@Seeker of Skybreak
+Kiki-Jiki, Mirror Breaker@Vizier of Tumbling Sands
+Kiki-Jiki, Mirror Breaker@Tidewater Minion
+Karakas@Emrakul, the Aeons Torn
+Time Vault@Voltaic Key
+Time Vault@Manifold Key
+Time Vault@Galvanic Key
+Time Vault@Clock of Omens
+Time Vault@Aphetto Alchemist
+Time Vault@Vizier of Tumbling Sands
+Time Vault@Fatestitcher
+Time Vault@Tidewater Minion
+Time Vault@Captain of the Mists
+Time Vault@Elder Druid
+Time Vault@Kiora's Follower
+Time Vault@Unbender Tine
+Time Vault@Ral Zarek
+Time Vault@Tezzeret the Seeker
+Time Vault@Teferi, Timebender
+Time Vault@Frenzied Fugue
+Time Vault@Filigree Sages
+Time Vault@Voltaic Servant
+Time Vault@Mind Over Matter
+Time Vault@Trickster Mage
+Time Vault@Telekinetic Bonds
+Summon the School@Paradox Engine
+Time Vault@Derevi, Empyrial Tactician
+Crackdown Construct@Mobilized District
+Crackdown Construct@Wandering Fumarole
+Crackdown Construct@Lavaclaw Reaches
+Loyal Retainers@Saffi Eriksdotter
+Swans of Bryn Argoll@Chain of Plasma
+Thromok the Insatiable@Chandra's Ignition
+Nexus of Fate@Divining Witch
+Nexus of Fate@Thought Lash
+Heartless Hidetsugu@Vizkopa Guildmage
+Niv-Mizzet, the Firemind@Swans of Bryn Argoll
+Sneak Attack@Palinchron
+Karakas@Zacama, Primal Calamity
+Ceaseless Searblades@Wandering Fumarole
+Drogskol Reaver@Horizon Chimera
+Wheel of Misfortune@Cho-Arrim Alchemist
+Wheel of Misfortune@Hallow
+Wheel of Misfortune@Intervention Pact
+Wheel of Misfortune@Purity
+Wheel of Misfortune@Samite Ministration
+Wheel of Misfortune@Reverse Damage
+Kiki-Jiki, Mirror Breaker@Port Razer
+Port Razer@Helm of the Host
+Port Razer@Brago, King Eternal
+Livio, Oathsworn Sentinel@Village Bell-Ringer
+Livio, Oathsworn Sentinel@Intruder Alarm
+Intruder Alarm@Flamewright
+Intruder Alarm@Ghoulcaller Gisa
+Intruder Alarm@Jund Battlemage
+Intruder Alarm@Imperious Perfect
+Intruder Alarm@Kazandu Tuskcaller
+Intruder Alarm@Lich Lord of Unx
+Intruder Alarm@Puppet Conjurer
+Intruder Alarm@Selesnya Evangel
+Intruder Alarm@Skirsdag High Priest
+Intruder Alarm@Tolsimir Wolfblood
+Intruder Alarm@Wall of Kelp
+Emiel the Blessed@Workhorse
+Cadaverous Bloom@Oath of Lim-Dûl
+Peer into the Abyss@Psychic Corrosion
+Enter the Infinite@Psychic Corrosion
+Cadaverous Bloom@Well of Knowledge
+Cadaverous Bloom@Idle Thoughts
+Ashaya, Soul of the Wild@Realm Razer
+Malcolm, Keen-Eyed Navigator@Glint-Horn Buccaneer
+Midnight Guard@Splinter Twin
+Kiki-Jiki, Mirror Breaker@Coercive Recruiter
+Port Razer@Splinter Twin
+Second Chance@Treasury Thrull
+Second Chance@Sun Titan
+Second Chance@Skull of Orm
+Second Chance@Silent Sentinel
+Second Chance@Hanna, Ship's Navigator
+Second Chance@Dowsing Shaman
+Jeska's Will@Reiterate
+Oath of Druids@Jace, Wielder of Mysteries
+Kodama of the East Tree@Meloku the Clouded Mirror
+Dargo, the Shipwrecker@Phyrexian Altar
+Dargo, the Shipwrecker@Thermopod
+Spawnsire of Ulamog@Ashnod's Altar
+Wildwood Scourge@Enduring Scalelord
+Fleet Swallower@Fraying Sanity
+Tawnos, Urza's Apprentice@Sands of Time
+Gray Merchant of Asphodel@Rite of Replication
+Cephalid Aristocrat@Lancers en-Kor
+Cephalid Aristocrat@Reconnaissance
+Cephalid Illusionist@Lancers en-Kor
+Cephalid Illusionist@Nomads en-Kor
+Cephalid Illusionist@Outrider en-Kor
+Cephalid Illusionist@Shaman en-Kor
+Cephalid Illusionist@Soltari Guerrillas
+Cephalid Illusionist@Spirit en-Kor
+Cephalid Illusionist@Warrior en-Kor
+Cephalid Illusionist@Reconnaissance
+Polyraptor@Aether Flash
+Opalescence@Day of the Dragons
+Marrow-Gnawer@Thornbite Staff
+Hamza, Guardian of Arashin@Ancestral Statue
+Metalworker@Voltaic Construct
+Magda, Brazen Outlaw@Aggravated Assault
+Kaya the Inexorable@Karn's Temporal Sundering
+Crackdown Construct@Dark Maze
+Crackdown Construct@Blinking Spirit
+Crackdown Construct@Shuko
+Crackdown Construct@Grafted Wargear
+Crackdown Construct@Shaman en-Kor
+Crackdown Construct@Flowstone Hellion
+Crackdown Construct@Hyalopterous Lemure
+Crackdown Construct@Jodah's Avenger
+Crackdown Construct@Frenetic Efreet
+Crackdown Construct@Urza's Avenger
+Crackdown Construct@Lancers en-Kor
+Crackdown Construct@Soltari Guerrillas
+Crackdown Construct@Warrior en-Kor
+Crackdown Construct@Knowledge Vault
+Crackdown Construct@Mist Dragon
+Crackdown Construct@Viscid Lemures
+Crackdown Construct@Spirit en-Kor
+Crackdown Construct@Hopping Automaton
+Crackdown Construct@Frenetic Sliver
+Crackdown Construct@Outrider en-Kor
+Crackdown Construct@Varchild's Crusader
+Crackdown Construct@Personal Incarnation
+Crackdown Construct@Nomads en-Kor
+Triskelion@Scythe of the Wretched
+Sliver Queen@Basal Sliver
+Sliver Queen@Ashnod's Altar
+Power Artifact@Grim Monolith
+Power Artifact@Basalt Monolith
+Wanderwine Prophets@Followed Footsteps
+Wanderwine Prophets@Stonybrook Schoolmaster
+Bellowing Aegisaur@Walking Ballista
+Bellowing Aegisaur@Triskelion
+Spike Feeder@Light of Promise
+Minion Reflector@Worldgorger Dragon
+Mischievous Quanar@Turnabout
+Earthcraft@Grinning Ignus
+Goldspan Dragon@Crown of Flames
+Goldspan Dragon@Flickering Ward
+Goldspan Dragon@Shimmering Wings
+Goldspan Dragon@Whip Silk
+Rasputin Dreamweaver@Emiel the Blessed
+Body of Knowledge@Niv-Mizzet, the Firemind
+Body of Knowledge@Niv-Mizzet, Parun
+Tidewater Minion@Illusionist's Bracers
+Liliana, Untouched by Death@Phyrexian Altar
+Lightning Greaves@Crackdown Construct
+Animar, Soul of Elements@Palinchron
+Hellkite Charger@Sword of Feast and Famine
+Conspiracy@Glorious Protector
+Conspiracy@Restoration Angel
+Blazing Sunsteel@Brash Taunter
+Nevinyrral, Urborg Tyrant@Phyrexian Altar
+Polyraptor@Goblin Bombardment
+Intruder Alarm@Hell's Caretaker
+Reverberate@Dual Strike
+Leonin Relic-Warder@Dance of Many
+Day of the Dragons@Starfield of Nyx
+Hullbreacher@Teferi's Puzzle Box
+Dockside Extortionist@Capsize
+Sharuum the Hegemon@Body Double
+Sharuum the Hegemon@Clever Impersonator
+Sharuum the Hegemon@Clone
+Sharuum the Hegemon@Copy Artifact
+Sharuum the Hegemon@Evil Twin
+Sharuum the Hegemon@Gigantoplasm
+Sharuum the Hegemon@Glasspool Mimic // Glasspool Shore
+Sharuum the Hegemon@Mercurial Pretender
+Sharuum the Hegemon@Mirror Image
+Sharuum the Hegemon@Mirrormade
+Sharuum the Hegemon@Mirror of the Forebears
+Sharuum the Hegemon@Phantasmal Image
+Sharuum the Hegemon@Phyrexian Metamorph
+Sharuum the Hegemon@Quicksilver Gargantuan
+Sharuum the Hegemon@Reflections of Littjara
+Sharuum the Hegemon@Sakashima's Protege
+Sharuum the Hegemon@Sakashima's Student
+Sharuum the Hegemon@Sculpting Steel
+Sharuum the Hegemon@Stunt Double
+Sharuum the Hegemon@Vesuvan Doppelganger
+Sharuum the Hegemon@Vesuvan Shapeshifter
+Sharuum the Hegemon@Vizier of Many Faces
+Sharuum the Hegemon@Wall of Stolen Identity
+Filigree Sages@Empowered Autogenerator
+Elemental Mastery@Midnight Guard
+Nadier, Agent of the Duskenel@Food Chain
+Professor Onyx@Chain of Smog
+Birgi, God of Storytelling // Harnfel, Horn of Bounty@Grinning Ignus
+Chain of Acid@Witherbloom Apprentice
+Chain of Acid@Professor Onyx
+Aggravated Assault@Selvala, Heart of the Wilds
+Proteus Staff@Nexus of Fate
+Proteus Staff@Beacon of Tomorrows
+Karrthus, Tyrant of Jund@Splinter Twin
+Splinter Twin@Derevi, Empyrial Tactician
+Auriok Salvagers@Black Lotus
+Plague of Vermin@Corpse Knight
+Rionya, Fire Dancer@Combat Celebrant
+Wake Thrasher@Aphetto Alchemist
+Prossh, Skyraider of Kher@Food Chain
+Dual Strike@Fork
+Dual Strike@Increasing Vengeance
+Dual Strike@Insidious Will
+Dual Strike@Reiterate
+Dual Strike@Twincast
+Expansion // Explosion@Twincast
+Expansion // Explosion@Fork
+Twincast@Fork
+Twincast@Increasing Vengeance
+Fraying Omnipotence@Wound Reflection
+Fury Storm@Deekah, Fractal Theorist
+Fury Storm@Archmage Emeritus
+Fury Storm@Professor Onyx
+Fury Storm@Sedgemoor Witch
+Fury Storm@Storm-Kiln Artist
+Fury Storm@Witherbloom Apprentice
+Fury Storm@Witherbloom Pledgemage
+Twinning Staff@Narset's Reversal
+Double Major@Vadrok, Apex of Thunder
+Dualcaster Mage@Ghostly Flicker
+Turntimber Ranger@Maskwood Nexus
+Morophon, the Boundless@Shrieking Drake
+Rionya, Fire Dancer@Godo, Bandit Warlord
+Herd Baloth@Ivy Lane Denizen
+Herd Baloth@Cathars' Crusade
+Emiel the Blessed@Priest of Urabrask
+Emiel the Blessed@Priest of Gix
+Arcbond@Pariah
+Scurry Oak@Cathars' Crusade
+Scurry Oak@Ivy Lane Denizen
+Vrondiss, Rage of Ancients@Terror of the Peaks
+Old Gnawbone@Hellkite Charger
+Delina, Wild Mage@Medomai the Ageless
+Cleric Class@Spike Feeder
+Aggravated Assault@Old Gnawbone
+Najeela, the Blade-Blossom@Old Gnawbone
+Grimgrin, Corpse-Born@Elemental Mastery
+Doubling Season@Jace, Cunning Castaway
+Aluren@Aether Adept
+Aluren@Cavern Harpy
+Aluren@Fleetfoot Panther
+Aluren@Horned Kavu
+Aluren@Lava Zombie
+Aluren@Man-o'-War
+Aluren@Shrieking Drake
+Aluren@Silver Drake
+Aluren@Stonecloaker
+Aluren@Whitemane Lion
+Kroxa, Titan of Death's Hunger@Worldfire
+Selvala, Heart of the Wilds@Gauntlets of Light
+Dual Casting@Traitorous Greed
+Teferi, Who Slows the Sunset@The Chain Veil
+Halana and Alena, Partners@Sage of Hours
+Dominating Vampire@Splinter Twin
+Weaver of Blossoms // Blossom-Clad Werewolf@Freed from the Real
+Weaver of Blossoms // Blossom-Clad Werewolf@Pemmin's Aura
+Wedding Ring@Consecrated Sphinx
+Chain of Smog@Witherbloom Apprentice
+Brass's Bounty@Reiterate
+Ill-Tempered Loner // Howlpack Avenger@Stuffy Doll
+Medomai the Ageless@Phantom Steed
+Brion Stoutarm@Enduring Angel // Angelic Enforcer
+Brion Stoutarm@Soul of Eternity
+Brion Stoutarm@Serra Avatar
+Fling@Enduring Angel // Angelic Enforcer
+Fling@Soul of Eternity
+Fling@Serra Avatar
+Grand Warlord Radha@Aggravated Assault
+Goblin Welder@Thornbite Staff
+Goblin Welder@Intruder Alarm
+Workhorse@Eldrazi Displacer
+Traxos, Scourge of Kroog@Banishing Knack
+Ranar the Ever-Watchful@Portcullis
+Acererak the Archlich@Aluren
+Acererak the Archlich@Rooftop Storm
+Myr Welder@Time Vault
+Mairsil, the Pretender@Time Vault
+Enduring Angel // Angelic Enforcer@Vito, Thorn of the Dusk Rose
+Zethi, Arcane Blademaster@Savage Beating
+Devoted Druid@Swift Reconfiguration
+Sanctum Weaver@Pemmin's Aura
+Sanctum Weaver@Freed from the Real
+Bladewing the Risen@Reflections of Littjara
+Enter the Infinite@Thassa's Oracle
+Village Bell-Ringer@Deadeye Navigator
+Incubation Druid@Pemmin's Aura
+Incubation Druid@Freed from the Real
+Village Bell-Ringer@Emiel the Blessed
+Soulfire Grand Master@Reset
+Soulfire Grand Master@Dramatic Reversal
+Village Bell-Ringer@Eldrazi Displacer
+Storm-Kiln Artist@Haze of Rage
+Splinter Twin@Faces of the Past
+Vigean Graftmage@Incubation Druid
+Vigean Graftmage@Bloom Tender
+Vigean Graftmage@Faeburrow Elder
+Blinkmoth Infusion@Lithoform Engine
+Blinkmoth Infusion@Reiterate
+Go-Shintai of Life's Origin@Second Chance
+Rionya, Fire Dancer@Lightning Runner
+Kazuul's Fury // Kazuul's Cliffs@Serra Avatar
+Crystalline Crawler@Evolution Vat
+Thud@Enduring Angel // Angelic Enforcer
+Shabraz, the Skyshark@Lich's Mastery
+Shabraz, the Skyshark@Lich
+Xathrid Demon@Enduring Angel // Angelic Enforcer
+Thud@Soul of Eternity
+Xathrid Demon@Soul of Eternity
+Xathrid Demon@Serra Avatar
+Lava Zombie@Rooftop Storm
+Sedraxis Alchemist@Rooftop Storm
+Chulane, Teller of Tales@Intruder Alarm
+Voice of the Woods@Intruder Alarm
+Thud@Serra Avatar
+Light of Promise@Triskelion
+Light of Promise@Walking Ballista
+Fathom Mage@Wizard Class
+Intruder Alarm@Elemental Mastery
+Frenetic Efreet@Tavern Scoundrel
+Fiendlash@Guilty Conscience
+Elemental Mastery@Black Carriage
+Enduring Angel // Angelic Enforcer@Vizkopa Guildmage
+Elemental Mastery@Altar Golem
+Axebane Guardian@High Alert
+Slimefoot, the Stowaway@Mana Echoes
+Myr Matrix@Mana Echoes
+Lord Xander, the Collector@Bruvac the Grandiloquent
+Sky Hussar@Eldrazi Displacer
+Grimgrin, Corpse-Born@Presence of Gond
+Selvala, Heart of the Wilds@High Alert
+Sky Hussar@Emiel the Blessed
+Faeburrow Elder@High Alert
+Bloom Tender@High Alert
+Rapacious Dragon@Deadeye Navigator
+Faeburrow Elder@Gauntlets of Light
+Prosperous Pirates@Deadeye Navigator
+Bloom Tender@Gauntlets of Light
+Eloise, Nephalia Sleuth@March of the Machines
+Sky Hussar@Deadeye Navigator
+Kamahl, Pit Fighter@Scythe of the Wretched
+Fable of the Mirror-Breaker // Reflection of Kiki-Jiki@Timestream Navigator
+Kiki-Jiki, Mirror Breaker@Helm of the Host
+Feldon of the Third Path@Timestream Navigator
+Kiki-Jiki, Mirror Breaker@Double Major
+Kiki-Jiki, Mirror Breaker@Augmenter Pugilist // Echoing Equation
+Teferi, Who Slows the Sunset@Lithoform Engine
+Bruvac the Grandiloquent@Traumatize
+Lord Xander, the Collector@Fraying Sanity
+Chandra's Ignition@Enduring Angel // Angelic Enforcer
+Chandra's Ignition@Soul of Eternity
+Chandra's Ignition@Serra Avatar
+Grab the Reins@Enduring Angel // Angelic Enforcer
+Grab the Reins@Soul of Eternity
+Grab the Reins@Serra Avatar
+Kazuul's Fury // Kazuul's Cliffs@Enduring Angel // Angelic Enforcer
+Kazuul's Fury // Kazuul's Cliffs@Soul of Eternity
+Ghave, Guru of Spores@Mana Echoes
+Accomplished Alchemist@Freed from the Real
+Accomplished Alchemist@Pemmin's Aura
+Scourge of the Skyclaves@Warlock Class
+Niv-Mizzet, Parun@Helm of the Ghastlord
+Niv-Mizzet, the Firemind@Helm of the Ghastlord
+Famished Foragers@Emiel the Blessed
+Benthic Biomancer@Wizard Class
+The Locust God@Dire Undercurrents
+Cut Your Losses@Bruvac the Grandiloquent
+Cut Your Losses@Fraying Sanity
+Crackleburr@Cryptolith Rite
+Crackleburr@Song of Freyalise
+Devoted Druid@Luxior, Giada's Gift
+Leonin Relic-Warder@Enchanted Evening
+Bootleggers' Stash@Time Sieve
+Queza, Augur of Agonies@Lich
+Queza, Augur of Agonies@Lich's Mastery
+Tivit, Seller of Secrets@Deadeye Navigator
+Vigean Graftmage@Krosan Restorer
+Mikaeus, the Unhallowed@Cinderhaze Wretch
+Mikaeus, the Unhallowed@Barrenton Medic
+Mikaeus, the Unhallowed@Devoted Druid
+Kiki-Jiki, Mirror Breaker@Teardrop Kami
+Splinter Twin@Teardrop Kami
+Shrieking Drake@Chakram Retriever
+Stuffy Doll@Blazing Sunsteel
+Boros Reckoner@Blazing Sunsteel
+Boros Reckoner@Fiendlash
+Spitemare@Blazing Sunsteel
+Spitemare@Fiendlash
+Truefire Captain@Blazing Sunsteel
+Sun-Crowned Hunters@Blazing Sunsteel
+Ill-Tempered Loner // Howlpack Avenger@Blazing Sunsteel
+Ill-Tempered Loner // Howlpack Avenger@Fiendlash
+Mogg Maniac@Blazing Sunsteel
+Broodhatch Nantuko@Terror of the Peaks
+Broodhatch Nantuko@Warstorm Surge
+Saber Ants@Terror of the Peaks
+Saber Ants@Warstorm Surge
+Hornet Nest@Terror of the Peaks
+Hornet Nest@Warstorm Surge
+Overgrown Armasaur@Terror of the Peaks
+Overgrown Armasaur@Warstorm Surge
+Jadzi, Oracle of Arcavios // Journey to the Oracle@Uyo, Silent Prophet
+Sphinx of the Second Sun@Aggravated Assault
+Chatterfang, Squirrel General@Pitiless Plunderer
+Storm-Kiln Artist@Chain of Smog
+Storm-Kiln Artist@Chain of Acid
+Adarkar Valkyrie@Teardrop Kami
+Enduring Scalelord@Spark Double
+Enduring Scalelord@Altered Ego
+Enduring Scalelord@Moritte of the Frost
+Sedgemoor Witch@Chain of Smog
+Sedgemoor Witch@Chain of Acid
+Jarad, Golgari Lich Lord@Serra Avatar
+Jarad, Golgari Lich Lord@Soul of Eternity
+Jarad, Golgari Lich Lord@Enduring Angel // Angelic Enforcer
+Jarad, Golgari Lich Lord@Wall of Blood
+Jarad, Golgari Lich Lord@Hatred
+Gisela, Blade of Goldnight@Heartless Hidetsugu
+Varragoth, Bloodsky Sire@Nexus of Fate
+Varragoth, Bloodsky Sire@Beacon of Tomorrows
+Sage of Hours@Clockspinning
+Lich@Soul Conduit
+Dualcaster Mage@Saw in Half
+Naru Meha, Master Wizard@Saw in Half
+Lich@Axis of Mortality
+Morophon, the Boundless@Cavern Harpy
+Worldfire@Mogis, God of Slaughter
+Worldfire@Nekusar, the Mindrazer
+Worldfire@Marath, Will of the Wild
+Worldfire@Outpost Siege
+Splinter Twin@Intruder Alarm
+Mana Echoes@Emiel the Blessed
+Mana Echoes@Eldrazi Displacer
+Niv-Mizzet, Parun@Snake Umbra
+Niv-Mizzet, the Firemind@Snake Umbra
+Aurelia, the Warleader@Sword of Hearth and Home
+Sanctum Weaver@Gauntlets of Light
+Phantom Steed@Port Razer
+Selvala, Heart of the Wilds@Freed from the Real
+Selvala, Heart of the Wilds@Pemmin's Aura
+Wanderwine Prophets@Maskwood Nexus
+Kiki-Jiki, Mirror Breaker@Kelpie Guide
+Metalworker@Cogwork Assembler
+Ashaya, Soul of the Wild@Quirion Ranger
+Sasaya, Orochi Ascendant // Sasaya's Essence@Wakeroot Elemental
+Blood Pet@Enduring Renewal
+Wild Cantor@Enduring Renewal
+Immaculate Magistrate@Sage of Hours
+Sanctum Weaver@High Alert
+Astarion, the Decadent@Peer into the Abyss
+Astarion, the Decadent@Fraying Omnipotence
+Astarion, the Decadent@Quietus Spike
+Astarion, the Decadent@Raving Dead
+Astarion, the Decadent@Scourge of the Skyclaves
+Astarion, the Decadent@Virtus the Veiled
+Astarion, the Decadent@Scytheclaw
+Silvanus's Invoker@Gaea's Cradle
+Silvanus's Invoker@Growing Rites of Itlimoc // Itlimoc, Cradle of the Sun
+Silvanus's Invoker@Serra's Sanctum
+Silvanus's Invoker@Storm the Vault // Vault of Catlacan
+Silvanus's Invoker@Tolarian Academy
+Myrkul, Lord of Bones@Devoted Druid
+Abdel Adrian, Gorion's Ward@Animate Dead
+Naru Meha, Master Wizard@Blur
+Dualcaster Mage@Blur
+Polyraptor@Where Ancients Tread
+Lord of the Forsaken@Cut // Ribbons
+Endless Horizons@Goblin Charbelcher
+Tooth and Claw@Chatterfang, Squirrel General
+Grand Warlord Radha@Hellkite Charger
+Icewind Stalwart@Conspiracy
+Vhal, Candlekeep Researcher@Staff of Domination
+Vhal, Candlekeep Researcher@Umbral Mantle
+Vhal, Candlekeep Researcher@Sword of the Paruns
+Miirym, Sentinel Wyrm@Worldgorger Dragon
+Reckless Barbarian@Enduring Renewal
+Abdel Adrian, Gorion's Ward@Dance of the Dead
+Abdel Adrian, Gorion's Ward@Necromancy
+Wedding Ring@Psychic Possession
+Astral Dragon@Cursed Mirror
+Astral Dragon@Journey to Nowhere
+Astral Dragon@Oblivion Ring
+Astral Dragon@Parallax Wave
+Myrkul, Lord of Bones@Astral Dragon
+Astral Dragon@Dance of Many
+Jan Jansen, Chaos Crafter@Intruder Alarm
+Vhal, Candlekeep Researcher@Singing Bell Strike
+Abdel Adrian, Gorion's Ward@Deadeye Navigator
+Abdel Adrian, Gorion's Ward@Emiel the Blessed
+Abdel Adrian, Gorion's Ward@Eldrazi Displacer
+Rionya, Fire Dancer@Port Razer
+Delina, Wild Mage@Port Razer
+Marwyn, the Nurturer@Singing Bell Strike
+Selvala, Heart of the Wilds@Singing Bell Strike
+Circle of Dreams Druid@Singing Bell Strike
+Heronblade Elite@Singing Bell Strike
+Viridian Joiner@Singing Bell Strike
+Alena, Kessig Trapper@Singing Bell Strike
+Kiki-Jiki, Mirror Breaker@Delina, Wild Mage
+Nested Ghoul@Terror of the Peaks
+Nested Ghoul@Warstorm Surge
+Nested Ghoul@Pandemonium
+Thrasta, Tempest's Roar@Food Chain
+Slogurk, the Overslime@Mind Over Matter
+Combat Celebrant@Mirage Phalanx
+Living Plane@Massacre Wurm
+Dualcaster Mage@Settle Beyond Reality
+Naru Meha, Master Wizard@Settle Beyond Reality
+Dualcaster Mage@Siren's Ruse
+Naru Meha, Master Wizard@Siren's Ruse
+Myojin of Cryptic Dreams@Dramatist's Puppet
+Myojin of Cryptic Dreams@Throne of Geth
+Lurking Roper@Sorcerer's Wand
+Breath of Fury@Goblin Rabblemaster
+Crypt Champion@Phantasmal Image
+Crypt Champion@Glasspool Mimic // Glasspool Shore
+Crypt Champion@Mirror Image
+Chain of Acid@Archmage Emeritus
+Chain of Smog@Deekah, Fractal Theorist
+Chain of Acid@Deekah, Fractal Theorist
+Volcano Hellion@True Conviction
+Volcano Hellion@Heliod, Sun-Crowned
+Goldspan Dragon@View from Above
+Traxos, Scourge of Kroog@Retraction Helix
+Scytheclaw@Wound Reflection
+Scytheclaw@Archfiend of Despair
+Scytheclaw@Warlock Class
+Quietus Spike@Wound Reflection
+Quietus Spike@Archfiend of Despair
+Quietus Spike@Warlock Class
+Virtus the Veiled@Archfiend of Despair
+Virtus the Veiled@Warlock Class
+Raving Dead@Wound Reflection
+Raving Dead@Archfiend of Despair
+Raving Dead@Warlock Class
+Ruin Ghost@Retreat to Coralhelm
+Rakka Mar@Intruder Alarm
+Ripjaw Raptor@Niv-Mizzet, Parun
+Ripjaw Raptor@Niv-Mizzet, the Firemind
+Kelpie Guide@Freed from the Real
+Kelpie Guide@Pemmin's Aura
+Medomai the Ageless@Satoru Umezawa
+Minsc & Boo, Timeless Heroes@Serra Avatar
+Minsc & Boo, Timeless Heroes@Soul of Eternity
+Minsc & Boo, Timeless Heroes@Enduring Angel // Angelic Enforcer
+Frilled Deathspitter@Guilty Conscience
+Sun-Crowned Hunters@Guilty Conscience
+Spelljack@Swarm Intelligence
+Spelljack@Bonus Round
+Aeve, Progenitor Ooze@Food Chain
+Martyrdom@Arcbond
+Felidar Guardian@Flameshadow Conjuring
+Sakashima of a Thousand Faces@Felidar Guardian
+Animar, Soul of Elements@Primordial Mist
+The Locust God@Rite of Harmony
+Heartless Hidetsugu@Curse of Bloodletting
+Heartless Hidetsugu@Bitter Feud
+Heartless Hidetsugu@Goblin Goliath
+Satoru Umezawa@Master of Cruelties
+Toralf, God of Fury // Toralf's Hammer@Star of Extinction
+Black Carriage@Presence of Gond
+Black Carriage@Splinter Twin
+Phantom Steed@Dual Nature
+Orah, Skyclave Hierophant@Infinite Reflection
+Pili-Pala@Careful Cultivation
+Farmstead Gleaner@Careful Cultivation
+Composite Golem@Fool's Demise
+Intruder Alarm@Jade Mage
+Intruder Alarm@Biogenic Ooze
+Morality Shift@Mortal Combat
+Ivy Lane Denizen@Aerie Ouphes
+Cathars' Crusade@Aerie Ouphes
+Niv-Mizzet, the Firemind@Illusory Ambusher
+Niv-Mizzet, Parun@Illusory Ambusher
+Walking Ballista@Sunbond
+Triskelion@Sunbond
+Lightning Runner@Infinite Reflection
+Old Gnawbone@Time Sieve
+Jace, Cunning Castaway@Vorinclex, Monstrous Raider
+Worldgorger Dragon@Worldfire
+Wrathful Red Dragon@Star of Extinction
+Drogskol Reaver@Confessor
+Drogskol Reaver@Feast of Sanity
+Jace, Wielder of Mysteries@Enter the Infinite
+Mind Over Matter@Idol of Oblivion
+Terror of the Peaks@Rite of Replication
+Scourge of Valkas@Rite of Replication
+Druids' Repository@Aggravated Assault
+Hellkite Charger@Druids' Repository
+Weaver of Harmony@Intruder Alarm
+Baral's Expertise@Dualcaster Mage
+Naru Meha, Master Wizard@Baral's Expertise
+Magar of the Magic Strings@Time Warp
+Magar of the Magic Strings@Temporal Manipulation
+Olivia's Attendants@Time Sieve
+Sophina, Spearsage Deserter@Time Sieve
+Surge to Victory@Savage Beating
+Dominating Vampire@Kiki-Jiki, Mirror Breaker
+Duke Ulder Ravengard@Port Razer
+Archmage Ascension@Nexus of Fate
+Archmage Ascension@Beacon of Tomorrows
+Emrakul's Hatcher@Emiel the Blessed
+Emrakul's Hatcher@Eldrazi Displacer
+Mercurial Pretender@Dockside Extortionist
+Disciple of Bolas@Body of Research
+Greater Good@Body of Research
+Sheoldred, the Apocalypse@Peer into the Abyss
+Drogskol Reaver@Sheoldred, the Apocalypse
+Sheoldred, the Apocalypse@Lich
+Sheoldred, the Apocalypse@Lich's Mastery
+Sheoldred, the Apocalypse@Nefarious Lich
+The Reaver Cleaver@Time Sieve
+The Reaver Cleaver@Aggravated Assault
+Najeela, the Blade-Blossom@The Reaver Cleaver
+The Reaver Cleaver@Hellkite Charger
+Filigree Sages@Timeless Lotus
+Estrid, the Masked@The Peregrine Dynamo
+Gideon, Martial Paragon@The Peregrine Dynamo
+Teferi, Who Slows the Sunset@The Peregrine Dynamo
+Robaran Mercenaries@Kiki-Jiki, Mirror Breaker
+Jodah's Codex@Mind Over Matter
+Briar Hydra@Sage of Hours
+Magar of the Magic Strings@Savage Beating
+Sevinne, the Chronoclasm@Increasing Vengeance
+Sevinne, the Chronoclasm@Refuse // Cooperate
+Brash Taunter@Aetherflux Reservoir
+Ashaya, Soul of the Wild@Petravark
+Fury Storm@Twinning Staff
+Kianne, Dean of Substance // Imbraham, Dean of Theory@Intruder Alarm
+Najeela, the Blade-Blossom@Esika, God of the Tree // The Prismatic Bridge
+Duskmantle Guildmage@Maddening Cacophony
+Feast of Sanity@Peer into the Abyss
+Vrondiss, Rage of Ancients@Warstorm Surge
+Vrondiss, Rage of Ancients@Pandemonium
+Archangel of Thune@Walking Ballista
+Archangel of Thune@Triskelion
+Marneus Calgar@The Locust God
+Leonin Relic-Warder@Biotransference
+Beacon of Immortality@Plague Drone
+Trazyn the Infinite@Time Vault
+Shard of the Nightbringer@Wound Reflection
+Shard of the Nightbringer@Archfiend of Despair
+Shard of the Nightbringer@Warlock Class
+Shard of the Nightbringer@Sanguine Bond
+Vito, Thorn of the Dusk Rose@Shard of the Nightbringer
+Rhys the Redeemed@Intruder Alarm
+Palinchron@Reflections of Littjara
+Belisarius Cawl@Intruder Alarm
+Cybernetica Datasmith@Intruder Alarm
+Time Sieve@Inquisitor Eisenhorn
+Blazing Sunsteel@Mirrormade
+Blazing Sunsteel@Guilty Conscience
+Blazing Sunsteel@Mirage Mirror
+Body of Research@Thud
+Body of Research@Kazuul's Fury // Kazuul's Cliffs
+Body of Research@Fling
+Body of Research@Grab the Reins
+Body of Research@Chandra's Ignition
+Palisade Giant@Arcbond
+Intruder Alarm@Ancestral Statue
+Rootha, Mercurial Artist@Refuse // Cooperate
+Rootha, Mercurial Artist@Twincast
+Rootha, Mercurial Artist@Fork
+Rootha, Mercurial Artist@Reverberate
+Rootha, Mercurial Artist@Increasing Vengeance
+Vadrok, Apex of Thunder@Chef's Kiss
+Scurry Oak@Coat of Arms
+Sharuum the Hegemon@Infinite Reflection
+Guile@Flusterstorm
+Extus, Oriq Overlord // Awaken the Blood Avatar@Chain of Smog
+Young Necromancer@Altar of Dementia
+Murderous Redcap@Solemnity
+Mirror-Mad Phantasm@Phantasmal Image
+Mirror-Mad Phantasm@Renegade Doppelganger
+Flumph@Niv-Mizzet, the Firemind
+Flumph@Niv-Mizzet, Parun
+Volo, Guide to Monsters@Palinchron
+Last Voyage of the _____@Worldgorger Dragon
+Leonin Relic-Warder@Last Voyage of the _____
+Abdel Adrian, Gorion's Ward@Last Voyage of the _____
+Devoted Druid@Captain Rex Nebula
+Bladewing the Risen@Cursed Mirror
+Bladewing the Risen@Clone
+Shabraz, the Skyshark@Nefarious Lich
+Sliver Queen@Intruder Alarm
+Myr Matrix@Intruder Alarm
+Bladewing the Risen@Necroduality
+Bladewing the Risen@Dual Nature
+Apex Altisaur@Outmuscle
+Apex Altisaur@Blizzard Brawl
+Apex Altisaur@Eldrazi Monument
+Apex Altisaur@Hammer of Nazahn
+Apex Altisaur@Darksteel Plate
+Vrondiss, Rage of Ancients@Dragon Tempest
+Flameshadow Conjuring@Worldgorger Dragon
+Rousing Refrain@Rift Elemental
+Sprouting Phytohydra@Blasting Station
+Sprouting Phytohydra@Goblin Bombardment
+Exchange of Words@Scute Swarm
+Vrondiss, Rage of Ancients@Scourge of Valkas
+Tooth and Claw@Adrix and Nev, Twincasters
+Arcbond@Pariah's Shield
+Tezzeret, Master of the Bridge@Ancestral Statue
+Fraying Omnipotence@Warlock Class
+Fraying Omnipotence@Archfiend of Despair
+Dualcaster Mage@Ephemerate
+Dualcaster Mage@Cloudshift
+Dualcaster Mage@Essence Flux
+Naru Meha, Master Wizard@Ephemerate
+Naru Meha, Master Wizard@Cloudshift
+Dualcaster Mage@Momentary Blink
+Dualcaster Mage@Justiciar's Portal
+Dualcaster Mage@Flicker of Fate
+Naru Meha, Master Wizard@Momentary Blink
+Naru Meha, Master Wizard@Justiciar's Portal
+Naru Meha, Master Wizard@Flicker of Fate
+Dualcaster Mage@Displace
+Machine God's Effigy@Devoted Druid
+Machine God's Effigy@Barrenton Medic
+Machine God's Effigy@Cinderhaze Wretch
+Hexavus@Devoted Druid
+Bruvac the Grandiloquent@Terisian Mindbreaker
+Terisian Mindbreaker@Fraying Sanity
+Drafna, Founder of Lat-Nam@Ugin's Nexus
+Deathbloom Ritualist@Freed from the Real
+Deathbloom Ritualist@Pemmin's Aura
+Dockside Extortionist@Meticulous Excavation
+Kiki-Jiki, Mirror Breaker@Corridor Monitor
+Volcano Hellion@Sorin, Vengeful Bloodlord
+Volcano Hellion@Whip of Erebos
+Sanctum Weaver@Thassa's Ire
+Murderous Redcap@Cathars' Crusade
+Port Razer@Mirage Phalanx
+Inner Fire@Reiterate
+Auntie Blyte, Bad Influence@Volcano Hellion
+Lita, Mechanical Engineer@The Peregrine Dynamo
+Nest of Scarabs@Blowfly Infestation
+Sporeweb Weaver@Blazing Sunsteel
+Tolsimir Wolfblood@Thornbite Staff
+Astral Dragon@Machine God's Effigy
+Palinchron@Phantasmal Image
+Teysa, Orzhov Scion@Sleight of Mind
+Teysa, Orzhov Scion@Whim of Volrath
+Teysa, Orzhov Scion@Alter Reality
+Teysa, Orzhov Scion@Crystal Spray
+Teysa, Orzhov Scion@Mind Bend
+Rionya, Fire Dancer@Bloodthirster
+Ill-Tempered Loner // Howlpack Avenger@Angelfire Ignition
+Spitemare@Angelfire Ignition
+Wirewood Symbiote@Maskwood Nexus
+Sharuum the Hegemon@Machine God's Effigy
+Norika Yamazaki, the Poet@Second Chance
+Kaya, Intangible Slayer@Felidar Guardian
+Guilty Conscience@Phyrexian Vindicator
+Conduit of Worlds@Second Chance
+All Will Be One@Quest for Pure Flame
+All Will Be One@The Red Terror
+Urabrask's Forge@Breath of Fury
+Henzie "Toolbox" Torre@Ancestral Statue
+Queza, Augur of Agonies@Nefarious Lich
+Jace's Archivist@Mind Over Matter
+Kwain, Itinerant Meddler@Mind Over Matter
+Magistrate's Scepter@Clock of Omens
+Neera, Wild Mage@Displacer Kitten
+Ith, High Arcanist@Mesmeric Orb
+Against All Odds@Dualcaster Mage
+Against All Odds@Naru Meha, Master Wizard
+Solphim, Mayhem Dominus@Heartless Hidetsugu
+All Will Be One@Night Dealings
+All Will Be One@Talon of Pain
+All Will Be One@War Elemental
+Unctus, Grand Metatect@Aphetto Alchemist
+Emiel the Blessed@Intruder Alarm
+Eldrazi Displacer@Intruder Alarm
+Deadeye Navigator@Intruder Alarm
+Zephyr Scribe@Retraction Helix
+Zephyr Scribe@Banishing Knack
+Replication Technique@Parallel Lives
+Replication Technique@Primal Vigor
+Replication Technique@Doubling Season
+Replication Technique@Anointed Procession
+Zalto, Fire Giant Duke@Blazing Sunsteel
+Loran of the Third Path@Mind Over Matter
+Urban Daggertooth@Walking Ballista
+Urban Daggertooth@Triskelion
+Urban Daggertooth@Deathbringer Thoctar
+Unctus, Grand Metatect@Pemmin's Aura
+Unctus, Grand Metatect@Freed from the Real
+Opalescence@Journey to Nowhere
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Peer into the Abyss
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Fraying Omnipotence
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Quietus Spike
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Raving Dead
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Scourge of the Skyclaves
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Virtus the Veiled
+Blitzwing, Cruel Tormentor // Blitzwing, Adaptive Assailant@Scytheclaw
+Riku of Two Reflections@Worldgorger Dragon
+Ith, High Arcanist@Wake Thrasher
+Aurelia, the Warleader@Rionya, Fire Dancer
+Niv-Mizzet, Parun@Swans of Bryn Argoll
+Brion Stoutarm@Body of Research
+Sunstrike Legionnaire@Splinter Twin
+Sunstrike Legionnaire@Presence of Gond
+Sunstrike Legionnaire@Elemental Mastery
+Otherworld Atlas@Mind Over Matter
+Primordial Mist@Hamza, Guardian of Arashin
+Primordial Mist@Rakdos, Lord of Riots
+Time Sieve@Ria Ivor, Bane of Bladehold
+Unctus, Grand Metatect@Tidewater Minion
+Ith, High Arcanist@Unctus, Grand Metatect
+All Will Be One@Body of Research
+All Will Be One@Eternity Vessel
+Lagomos, Hand of Hatred@Breath of Fury
+Morophon, the Boundless@Horned Kavu
+Shadowheart, Dark Justiciar@Body of Research
+Enduring Renewal@Thermopod
+Goro-Goro and Satoru@Breath of Fury
+Mirrodin Besieged@Morality Shift
+Crackdown Construct@Kazuul's Toll Collector
+Crackdown Construct@Eater of the Dead
+Crackdown Construct@Aphetto Alchemist
+Lu Su, Wu Advisor@Mind Over Matter
+Mind Over Matter@Talas Researcher
+Mind Over Matter@Enclave Cryptologist
+Mind Over Matter@Urza's Blueprints
+Silvanus's Invoker@Nykthos, Shrine to Nyx
+Enduring Renewal@Skirk Prospector
+Myrel, Shield of Argive@Time Sieve
+Breath of Fury@Determined Iteration
+Kiki-Jiki, Mirror Breaker@Breath of Fury
+Breath of Fury@Splinter Twin
+Rionya, Fire Dancer@Breath of Fury
+Breath of Fury@Daring Piracy
+Breath of Fury@Loyal Apprentice
+Valduk, Keeper of the Flame@Breath of Fury
+Blessed Wind@Archfiend of Despair
+Blessed Wind@Wound Reflection
+Blessed Wind@Warlock Class
+Magister Sphinx@Archfiend of Despair
+Magister Sphinx@Wound Reflection
+Magister Sphinx@Warlock Class
+Magar of the Magic Strings@Capture of Jingzhou
+Magar of the Magic Strings@Walk the Aeons
+Tainted Sigil@Aetherflux Reservoir
+Akki Battle Squad@Sword of Hearth and Home
+Brago, King Eternal@Akki Battle Squad
+Kiki-Jiki, Mirror Breaker@Janjeet Sentry
+Crackdown Construct@Martyrdom
+Dockside Extortionist@Disappear
+Sanctum Weaver@Seedcradle Witch
+The One Ring@Mind Over Matter
+Volo, Itinerant Scholar@Mind Over Matter
+Volrath, the Shapestealer@Patron of the Orochi
+Unctus, Grand Metatect@Tolarian Kraken
+Restoration Angel@Icewind Stalwart
+Ad Nauseam@Cloudsteel Kirin
+Magistrate's Scepter@Ichormoon Gauntlet
+Najeela, the Blade-Blossom@Cyclonus, the Saboteur // Cyclonus, Cybertronian Fighter
+Cyclonus, the Saboteur // Cyclonus, Cybertronian Fighter@Aggravated Assault
+Hermit Druid@Nexus of Fate
+Hermit Druid@Beacon of Tomorrows
+Leveler@Nexus of Fate
+Leveler@Beacon of Tomorrows
+Surrak and Goreclaw@Aerie Ouphes
+Kami of Whispered Hopes@Freed from the Real
+Kami of Whispered Hopes@Pemmin's Aura
+Kami of Whispered Hopes@Crab Umbra
+Kami of Whispered Hopes@High Alert
+Tribute to the World Tree@Aerie Ouphes
+Xerex Strobe-Knight@Intruder Alarm
+Omen Hawker@Pemmin's Aura
+Omen Hawker@Freed from the Real
+Sprouting Phytohydra@Marauding Raptor
+Sprouting Phytohydra@Aether Flash
+Kroxa and Kunoros@Altar of Dementia
+Shalai and Hallar@Heliod, Sun-Crowned
+Shalai and Hallar@Cleric Class
+Shalai and Hallar@Ajani's Pridemate
+Shalai and Hallar@Voice of the Blessed
+Shalai and Hallar@Celestial Unicorn
+Shalai and Hallar@Twinblade Paladin
+Shalai and Hallar@Ageless Entity
+Shalai and Hallar@Gideon's Company
+Shalai and Hallar@Trelasarra, Moon Dancer
+Shalai and Hallar@Archangel of Thune
+Weaver of Harmony@Awakening
+Weaver of Harmony@Curse of Bounty
+Shalai and Hallar@The Red Terror
+Hangar Scrounger@Aphetto Alchemist
+Shalai and Hallar@Phyrexian Devourer
+All Will Be One@Phyrexian Devourer
+Scourge of the Throne@Helm of the Host
+Rionya, Fire Dancer@Scourge of the Throne
+All Will Be One@Soul-Scar Mage
+Intruder Alarm@Aethersnipe
+Mirror-Mad Phantasm@Sakashima's Will
+Shalai and Hallar@War Elemental
+Ob Nixilis, Captive Kingpin@All Will Be One
+Ob Nixilis, Captive Kingpin@Shalai and Hallar
+Harnessed Snubhorn@Second Chance
+All Will Be One@Everlasting Torment
+Timestream Navigator@The Temporal Anchor
+Ashaya, Soul of the Wild@Wormfang Turtle
+Ashaya, Soul of the Wild@Wormfang Newt
+Chain Stasis@Faeburrow Elder
+Underworld Breach@Path of the Pyromancer
+Volrath, the Shapestealer@Akki Battle Squad
+Selfless Squire@Wheel of Misfortune
+Kaya, Intangible Slayer@Enchanted Evening
+Urabrask // The Great Work@Resourceful Defense
+Exalted Flamer of Tzeentch@Time Warp
+Exalted Flamer of Tzeentch@Temporal Manipulation
+Exalted Flamer of Tzeentch@Capture of Jingzhou
+Exalted Flamer of Tzeentch@Walk the Aeons
+Kiki-Jiki, Mirror Breaker@Akki Battle Squad
+Rionya, Fire Dancer@Akki Battle Squad
+Leonin Relic-Warder@Encroaching Mycosynth
+Fable of the Mirror-Breaker // Reflection of Kiki-Jiki@Village Bell-Ringer
+Fable of the Mirror-Breaker // Reflection of Kiki-Jiki@Intruder Alarm
+Akki Battle Squad@Helm of the Host
+Bladewing the Risen@Saw in Half
+Bladewing the Risen@Activated Sleeper
+Body of Research@Soul's Fire
+Famished Paladin@Porcuparrot
+Lurking Roper@Porcuparrot
+Famished Paladin@Viridian Longbow
+Famished Paladin@Burning Anger
+Famished Paladin@Hermetic Study
+Famished Paladin@Fire Whip
+Famished Paladin@Arcane Teachings
+Lurking Roper@Viridian Longbow
+Lurking Roper@Burning Anger
+Lurking Roper@Hermetic Study
+Lurking Roper@Fire Whip
+Lurking Roper@Arcane Teachings
+Ratadrabik of Urborg@Boromir, Warden of the Tower
+Rosie Cotton of South Lane@Herd Baloth
+Rosie Cotton of South Lane@Scurry Oak
+One Ring to Rule Them All@Body of Research
+Sakashima of a Thousand Faces@Ioreth of the Healing House
+Éomer, Marshal of Rohan@Blade of Selves
+Éomer, Marshal of Rohan@Legion Loyalty
+Meneldor, Swift Savior@Aurelia, the Warleader
+The Watcher in the Water@Greater Good
+Orcish Bowmasters@Peer into the Abyss
+Fall of Cair Andros@Star of Extinction
+Fall of Cair Andros@Blasphemous Act
+Marneus Calgar@The Watcher in the Water
+Heliod, the Radiant Dawn // Heliod, the Warped Eclipse@Ancestral Statue
+Ezzaroot Channeler@Ancestral Statue
+Feast of Sanity@Flumph
+Feast of Sanity@Illusory Ambusher
+Feast of Sanity@Ripjaw Raptor
+Charnelhoard Wurm@Time Warp
+Charnelhoard Wurm@Capture of Jingzhou
+Charnelhoard Wurm@Temporal Manipulation
+Charnelhoard Wurm@Walk the Aeons
+Charnelhoard Wurm@Second Chance
+Oviya Pashiri, Sage Lifecrafter@Intruder Alarm
+Rootha, Mercurial Artist@Expansion // Explosion
+Peer into the Abyss@Alhammarret's Archive
+Ith, High Arcanist@Ioreth of the Healing House
+Mirage Phalanx@Bloodthirster
+Archmage Emeritus@Chain of Smog
+Mirkwood Bats@Plague of Vermin
+Orthion, Hero of Lavabrink@Intruder Alarm
+There and Back Again@Vitu-Ghazi Guildmage
+Hangar Scrounger@Seeker of Skybreak
+Gilraen, Dúnedain Protector@Village Bell-Ringer
+The Watcher in the Water@Dire Undercurrents
+Peregrin Took@Summoning Station
+Intruder Alarm@Banishing Knack
+Intruder Alarm@Retraction Helix
+Ugin's Nexus@Masterful Replication
+Syr Gwyn, Hero of Ashvale@Crackdown Construct
+Crackdown Construct@Puresteel Paladin
+Duke Ulder Ravengard@Éomer, Marshal of Rohan
+Kaya, Intangible Slayer@Luxior, Giada's Gift
+Ill-Tempered Loner // Howlpack Avenger@Soul Link
+Spitemare@Soul Link
+Boros Reckoner@Soul Link
+Hoard Hauler@Aggravated Assault
+Hoard Hauler@Hellkite Charger
+Najeela, the Blade-Blossom@Hoard Hauler
+Hoard Hauler@Time Sieve
+Blazing Sunsteel@Metropolis Reformer
+Vodalian Wave-Knight@Benthic Biomancer
+Brinelin, the Moon Kraken@Mycosynth Golem
+Crackdown Construct@Belt of Giant Strength
+Mishra, Eminent One@Aetherflux Reservoir
+Heartless Hidetsugu@Archfiend of Despair
+Heartless Hidetsugu@Wound Reflection
+Heartless Hidetsugu@Warlock Class
+Orthion, Hero of Lavabrink@Fanatic of Mogis
+Orthion, Hero of Lavabrink@Gray Merchant of Asphodel
+Soulfire Grand Master@Jeska's Will
+Rionya, Fire Dancer@Terror of the Peaks
+Orthion, Hero of Lavabrink@Terror of the Peaks
+Rukarumel, Biologist@Intruder Alarm
+Mind Over Matter@Oracle's Insight
+Mind Over Matter@Ocular Halo
+Mind Over Matter@Quicksilver Dagger
+Protector of the Crown@Arcbond
+Lurking Roper@Heavy Arbalest
+Lurking Roper@Hypervolt Grasp
+Lurking Roper@Psionic Gift
+Lurking Roper@Power of Fire
+Lurking Roper@Wolfhunter's Quiver
+Lurking Roper@Lightning Prowess
+Lurking Roper@Quicksilver Dagger
+Famished Paladin@Heavy Arbalest
+Famished Paladin@Hypervolt Grasp
+Famished Paladin@Psionic Gift
+Famished Paladin@Power of Fire
+Famished Paladin@Wolfhunter's Quiver
+Famished Paladin@Lightning Prowess
+Famished Paladin@Quicksilver Dagger
+Aetherflux Reservoir@Myr Welder
+Trazyn the Infinite@Aetherflux Reservoir
+Aetherflux Reservoir@Skilled Animator
+Aetherflux Reservoir@Cyberdrive Awakener
+Aetherflux Reservoir@Animate Artifact
+Selvala, Explorer Returned@Tolarian Kraken
+Renata, Called to the Hunt@Aerie Ouphes
+Moritte of the Frost@Aerie Ouphes
+Ondu Spiritdancer@Enchanted Evening
+The Tenth Doctor@Rousing Refrain
+Éowyn, Shieldmaiden@Breath of Fury
+Body of Research@Altar of Dementia
+Overgrown Battlement@Singing Bell Strike
+Intruder Alarm@Jungle Patrol
+Dualcaster Mage@Scrollshift
+Naru Meha, Master Wizard@Scrollshift
+Breath of Fury@Helm of the Host
+Mishra, Eminent One@Breath of Fury
+Dualcaster Mage@Mirage Mockery
+River Song@Timestream Navigator
+Ashiok, Wicked Manipulator@Wall of Blood
+Orcish Bowmasters@Flumph
+Composer of Spring@Cloudstone Curio
+Mischievous Quanar@Brass's Bounty
+Mischievous Quanar@Reset
+Mischievous Quanar@Rude Awakening
+Phyrexian Devourer@Nexus of Fate
+Phyrexian Devourer@Beacon of Tomorrows
+Teach by Example@Increasing Vengeance
+Naru Meha, Master Wizard@Necromantic Selection
+Dualcaster Mage@Necromantic Selection
+Omarthis, Ghostfire Initiate@Spark Double
+Timestream Navigator@Planar Bridge
+Selvala, Heart of the Wilds@Crab Umbra
+Enduring Scalelord@Kiki-Jiki, Mirror Breaker
+Palinchron@Panharmonicon
+Palinchron@Elesh Norn, Mother of Machines
+Palinchron@Gauntlet of Power
+Palinchron@Mirari's Wake
+Palinchron@Mana Reflection
+Palinchron@Zendikar Resurgent
+Palinchron@Dictate of Karametra
+Enduring Scalelord@Splinter Twin
+Enduring Scalelord@Cackling Counterpart
+Enduring Scalelord@Quasiduplicate
+Enduring Scalelord@Croaking Counterpart
+Enduring Scalelord@Helm of the Host
+Enduring Scalelord@Lithoform Engine
+Felidar Guardian@Cursed Mirror
+Felidar Guardian@Machine God's Effigy
+Wispweaver Angel@Cursed Mirror
+Chain of Smog@Clever Lumimancer
+Chain of Smog@Dragonsguard Elite
+Chain of Smog@Eager First-Year
+Chain of Smog@Veyran, Voice of Duality
+Chain of Smog@Karok Wrangler
+Chain of Smog@Leonin Lightscribe
+Chain of Smog@Lorehold Pledgemage
+Chain of Smog@Quandrix Pledgemage
+Chain of Smog@Silverquill Apprentice
+Chain of Smog@Zaffai, Thunder Conductor
+Chain of Smog@Witherbloom Pledgemage
+Chain of Acid@Clever Lumimancer
+Chain of Acid@Dragonsguard Elite
+Chain of Acid@Eager First-Year
+Chain of Acid@Karok Wrangler
+Chain of Acid@Leonin Lightscribe
+Chain of Acid@Lorehold Pledgemage
+Chain of Acid@Quandrix Pledgemage
+Chain of Acid@Silverquill Apprentice
+Chain of Acid@Zaffai, Thunder Conductor
+Chain of Acid@Witherbloom Pledgemage
+Chain of Acid@Veyran, Voice of Duality
+Karn, Silver Golem@Aetherflux Reservoir
+Aetherflux Reservoir@Karn's Touch
+Aetherflux Reservoir@Tezzeret, Agent of Bolas
+Aetherflux Reservoir@Tezzeret, Betrayer of Flesh
+Aetherflux Reservoir@Toymaker
+Aetherflux Reservoir@Xenic Poltergeist
+Aetherflux Reservoir@Yotia Declares War
+Katsumasa, the Animator@Aetherflux Reservoir
+Deathbringer Thoctar@Heliod, Sun-Crowned
+Deathbringer Thoctar@Archangel of Thune
+Deathbringer Thoctar@Cleric Class
+Deathbringer Thoctar@Light of Promise
+Deathbringer Thoctar@Sunbond
+Hellkite Charger@Nature's Will
+Screams from Within@Warehouse Tabby
+Agatha of the Vile Cauldron@Spawnsire of Ulamog
+Peregrin Took@Experimental Confectioner
+Morophon, the Boundless@Grinning Ignus
+Screams from Within@Knight of Doves
+The World Tree@Purphoros, God of the Forge
+Donna Noble@Guilty Conscience
+Donna Noble@Spitemare
+Donna Noble@Boros Reckoner
+Donna Noble@Ill-Tempered Loner // Howlpack Avenger
+Olivia, Crimson Bride@Breath of Fury
+Ayara, Widow of the Realm // Ayara, Furnace Queen@Breath of Fury
+Ancestral Statue@Mana Echoes
+Patrol Signaler@Earthcraft
+Tooth and Claw@Mondrak, Glory Dominus
+Tooth and Claw@Queen Allenal of Ruadach
+Tameshi, Reality Architect@Second Chance
+Be'lakor, the Dark Master@Orthion, Hero of Lavabrink
+Be'lakor, the Dark Master@Rite of Replication
+Body of Research@Doom Weaver
+Dualcaster Mage@Illusionist's Stratagem
+Sporeweb Weaver@Warstorm Surge
+Sporeweb Weaver@Terror of the Peaks
+Sporeweb Weaver@Pandemonium
+Sporeweb Weaver@Goblin Bombardment
+Sporeweb Weaver@Blasting Station
+Mirror-Mad Phantasm@Dermotaxi
+Mirror-Mad Phantasm@Shameless Charlatan
+Mirror-Mad Phantasm@Unstable Shapeshifter
+Mirror-Mad Phantasm@Quasiduplicate
+Mirror-Mad Phantasm@Polymorphous Rush
+Mirror-Mad Phantasm@Absorb Identity
+Mirror-Mad Phantasm@Mirror of the Forebears
+Mirror-Mad Phantasm@Mirage Mirror
+Mirror-Mad Phantasm@Cephalid Facetaker
+Mirror-Mad Phantasm@Cursed Mirror
+Mirror-Mad Phantasm@Machine God's Effigy
+Crackdown Construct@Gigantoplasm
+Crackdown Construct@Mirror Entity
+Crackdown Construct@Chimeric Staff
+Crackdown Construct@Crypt Rats
+Crackdown Construct@Demonspine Whip
+Crackdown Construct@Illusionary Mask
+Crackdown Construct@Vengeful Archon
+Valki, God of Lies // Tibalt, Cosmic Impostor@Crackdown Construct
+Zacama, Primal Calamity@Stormfront Riders
+Polyraptor@Blasting Station
+Ojer Axonil, Deepest Might // Temple of Power@Pyrohemia
+Ojer Axonil, Deepest Might // Temple of Power@Warmonger
+Reins of Power@Sigil Tracer
+Reins of Power@Echo Mage
+Caesar, Legion's Emperor@Breath of Fury
+Paradox Engine@Shrieking Drake
+Paradox Engine@Whitemane Lion
+Sheoldred, the Apocalypse@Griselbrand
+Maze of Ith@Krosan Restorer
+Volcano Hellion@Vito, Thorn of the Dusk Rose
+Volcano Hellion@Vault of the Archangel
+Saheeli, the Sun's Brilliance@Intruder Alarm
+Sovereign Okinec Ahau@Sage of Hours
+Dino DNA@Dockside Extortionist
+Dino DNA@Palinchron
+Dino DNA@Great Whale
+Dino DNA@Mana Echoes
+Breath of Fury@Moira, Urborg Haunt
+Timestream Navigator@Leveler
+Timestream Navigator@Phyrexian Devourer
+Time Sieve@Cybermen Squadron
+Time Sieve@Legion Loyalty
+Omarthis, Ghostfire Initiate@Double Major
+Magmatic Galleon@Havoc Jester
+Magmatic Galleon@Mayhem Devil
+Time Sieve@Exsanguinator Cavalry
+The Master, Formed Anew@Palinchron
+Wanderwine Prophets@Deeproot Pilgrimage
+Carmen, Cruel Skymarcher@Breath of Fury
+Filigree Sages@Nyx Lotus
+The Enigma Jewel // Locus of Enlightenment@Basalt Monolith
+The Enigma Jewel // Locus of Enlightenment@Grim Monolith
+Cradle Clearcutter@Voltaic Construct
+Poetic Ingenuity@Aggravated Assault
+Peer into the Abyss@Bloodletter of Aclazotz
+Pili-Pala@Bigger on the Inside
+Farmstead Gleaner@Bigger on the Inside
+Felidar Guardian@Icewind Stalwart
+Charismatic Conqueror@Fractured Identity
+Saheeli, the Sun's Brilliance@Timestream Navigator
+Harried Dronesmith@Breath of Fury
+Doppelgang@Reiterate
+Doppelgang@Eternal Witness
+Doppelgang@Archaeomancer
+The Pride of Hull Clade@Body of Research
+Barbed Servitor@Volcano Hellion
+Spawnsire of Ulamog@Pitiless Plunderer
+Lonis, Genetics Expert@Extruder
+Kate Stewart@Soultether Golem
+Lonis, Genetics Expert@Rosie Cotton of South Lane
+Bloodletter of Aclazotz@Fraying Omnipotence
+Bloodletter of Aclazotz@Revival // Revenge
+Bloodletter of Aclazotz@Scourge of the Skyclaves
+Bloodletter of Aclazotz@Blood Tribute
+Bloodletter of Aclazotz@Quietus Spike
+Bloodletter of Aclazotz@Ebonblade Reaper
+Bloodletter of Aclazotz@Scytheclaw
+Bloodletter of Aclazotz@Virtus the Veiled
+Bloodletter of Aclazotz@Shard of the Nightbringer
+Basalt Monolith@Forensic Gadgeteer
+The Watcher in the Water@Kindred Discovery
+Crackdown Construct@Vish Kal, Blood Arbiter
+Griselbrand@Laboratory Maniac
+Griselbrand@Jace, Wielder of Mysteries
+Nick Valentine, Private Eye@March of the Machines
+Piper Wright, Publick Reporter@Time Sieve
+The Watcher in the Water@Sage of the Falls
+Tesak, Judith's Hellhound@Hellkite Charger
+Splinter Twin@Thornbite Staff
+Swarm Intelligence@Reiterate
+Thousand-Year Storm@Reiterate
+Starfield of Nyx@Parallax Wave
+Ognis, the Dragon's Lash@Time Sieve
+Lonis, Genetics Expert@Yotian Dissident
+Ojer Taq, Deepest Foundation // Temple of Civilization@Tooth and Claw
+Preston Garvey, Minuteman@Aggravated Assault
+Preston Garvey, Minuteman@Najeela, the Blade-Blossom
+Preston Garvey, Minuteman@Hellkite Charger
+Bristly Bill, Spine Sower@Crystalline Crawler
+Selvala, Eager Trailblazer@Freed from the Real
+Bloodletter of Aclazotz@Rush of Dread
+Ghired, Mirror of the Wilds@Midnight Guard
+Ghired, Mirror of the Wilds@Intruder Alarm
+Imodane, the Pyrohammer@Fire Covenant
+Bigger on the Inside@Staff of Domination
+Blasting Station@Raptor Hatchling
+Goblin Bombardment@Raptor Hatchling
+Animar, Soul of Elements@Hullbreaker Horror
+Shaun, Father of Synths@Aurelia, the Warleader
+Bristly Bill, Spine Sower@Devoted Druid
+Sharuum the Hegemon@Synth Infiltrator
+Five Hundred Year Diary@Filigree Sages
+Timestream Navigator@Planar Portal
+The Enigma Jewel // Locus of Enlightenment@Seeker of Skybreak
+The Enigma Jewel // Locus of Enlightenment@Aphetto Alchemist
+Peregrin Took@Nuka-Cola Vending Machine
+Cloud of Faeries@Deadeye Navigator
+Shrieking Drake@Oltec Matterweaver
+Calamity, Galloping Inferno@Port Razer
+Myr Propagator@Intruder Alarm
+Torgaar, Famine Incarnate@Bloodletter of Aclazotz
+Torgaar, Famine Incarnate@Wound Reflection
+Torgaar, Famine Incarnate@Archfiend of Despair
+Torgaar, Famine Incarnate@Warlock Class
+Marneus Calgar@Mana Echoes
+Tivit, Seller of Secrets@Time Sieve
+Kami of Whispered Hopes@Vigean Graftmage
+Yomiji, Who Bars the Way@Omarthis, Ghostfire Initiate
+Enduring Renewal@Omarthis, Ghostfire Initiate
+Stella Lee, Wild Card@Stella Lee, Wild Card
+Felhide Spiritbinder@Ondu Spiritdancer
+Chthonian Nightmare@Dockside Extortionist
+Silverclad Ferocidons@Mayhem Devil
+Crackdown Construct@Plate Armor
+Crackdown Construct@Arm-Mounted Anchor
+Ertha Jo, Frontier Mentor@Seeker of Skybreak
+Ertha Jo, Frontier Mentor@Aphetto Alchemist
+Ertha Jo, Frontier Mentor@Tidewater Minion
+Basking Broodscale@Mazirek, Kraul Death Priest
+Basking Broodscale@Cathars' Crusade
+Basking Broodscale@Rosie Cotton of South Lane
+Basking Broodscale@Battle of Hoover Dam
+Basking Broodscale@Ghost Lantern // Bind Spirit
+Touch the Spirit Realm@Opalescence
+Time Vault@Territory Forge
+Basking Broodscale@Blade of the Bloodchief
+Basking Broodscale@Necrosynthesis
+Disciple of Freyalise // Garden of Freyalise@Body of Research
+Cayth, Famed Mechanist@Intruder Alarm
+Izzet Generatorium@Mind Over Matter
+Breath of Fury@Siege-Gang Lieutenant
+Satya, Aetherflux Genius@Port Razer
+Greenbelt Rampager@Primal Prayers
+Chatterfang, Squirrel General@Shilgengar, Sire of Famine
+Shilgengar, Sire of Famine@Jinnie Fay, Jetmir's Second
+Dualcaster Mage@Eldrazi Confluence
+Naru Meha, Master Wizard@Eldrazi Confluence
+Ulamog's Dreadsire@Intruder Alarm
+Ezio Auditore da Firenze@Sorin Markov
+Ezio Auditore da Firenze@Tree of Perdition
+Ezio Auditore da Firenze@Magister Sphinx
+Lightning Runner@Stone Idol Generator
+Lightning Runner@Aetherwind Basker
+Sage of the Maze@Pemmin's Aura
+Experiment Kraj@Ioreth of the Healing House
+Part the Waterveil@Radiate
+Barren Glory@Renounce
+Breath of Fury@Desert Warfare
+Sorin of House Markov // Sorin, Ravenous Neonate@Beacon of Immortality
+Sorin of House Markov // Sorin, Ravenous Neonate@Revival // Revenge
+Edward Kenway@Time Sieve
+Enduring Tenacity@Beacon of Immortality
+Enduring Tenacity@Revival // Revenge
+Havi, the All-Father@Moritte of the Frost
+Enduring Angel // Angelic Enforcer@Enduring Tenacity
+Shard of the Nightbringer@Enduring Tenacity
+Screaming Nemesis@Blazing Sunsteel
+Screaming Nemesis@Guilty Conscience
+Timestream Navigator@Progenitor Mimic
+Body of Research@Season of Gathering
+Naru Meha, Master Wizard@Starfall Invocation
+Dualcaster Mage@Starfall Invocation
+Kitsa, Otterball Elite@Dramatic Reversal
+Twenty-Toed Toad@Peer into the Abyss
+Twenty-Toed Toad@Enter the Infinite
+Zinnia, Valley's Voice@Palinchron
+Wick, the Whorled Mind@Conspiracy
+Basking Broodscale@Sadistic Glee
+Sanctum Weaver@Aggravated Assault
+Weaver of Harmony@Virtue of Loyalty // Ardenvale Fealty
+Satya, Aetherflux Genius@Lightning Runner
+Charismatic Conqueror@Silverquill Lecturer
+Changeling Hero@Dual Nature
+Changeling Titan@Dual Nature
+Changeling Berserker@Dual Nature
+Retrofitter Foundry@Mana Echoes
+Chandra's Incinerator@Repercussion
+Anzrag, the Quake-Mole@Last Night Together
+Ghyrson Starn, Kelermorph@Boros Reckoner
+Ghyrson Starn, Kelermorph@Spitemare
+Stormsplitter@Sprout Swarm
+Hazel's Brewmaster@Devoted Druid
+The Jolly Balloon Man@Village Bell-Ringer
+The Jolly Balloon Man@Intruder Alarm
+Razorkin Needlehead@Peer into the Abyss
+Piper Wright, Publick Reporter@Sage of Hours
+Najeela, the Blade-Blossom@Shriekwood Devourer
+Aggravated Assault@Shriekwood Devourer
+Hellkite Charger@Shriekwood Devourer
+Alania, Divergent Storm@Flare of Duplication
+Uyo, Silent Prophet@Doppelgang
+Arabella, Abandoned Doll@Storm Herd
+Wedding Ring@Notion Thief
+Aggravated Assault@Wirewood Channeler
+Enchanted Evening@Ghostly Dancers
+Anzrag, the Quake-Mole@Anara, Wolvid Familiar
+Blasphemous Act@Repercussion
+Soulfire Grand Master@Brass's Bounty
+Dragon Tempest@Ancient Gold Dragon
+Cavern-Hoard Dragon@Time Sieve
+The Mindskinner@Body of Research
+The Mindskinner@Serra Avatar
+The Mindskinner@Soul of Eternity
+The Mindskinner@Enduring Angel // Angelic Enforcer
+Grievous Wound@Wound Reflection
+Grievous Wound@Archfiend of Despair
+Grievous Wound@Warlock Class
+Grievous Wound@Bloodletter of Aclazotz
+Shaman of the Great Hunt@Mind Over Matter
+Marvin, Murderous Mimic@Splinter Twin
+Tarrian's Soulcleaver@Basking Broodscale
+Ondu Spiritdancer@Secret Arcade // Dusty Parlor
+Secret Arcade // Dusty Parlor@Ghostly Dancers
+Vito, Thorn of the Dusk Rose@Beacon of Immortality
+Vito, Thorn of the Dusk Rose@Revival // Revenge
+Marvin, Murderous Mimic@Ioreth of the Healing House
+Marina Vendrell's Grimoire@Horizon Chimera
+Harabaz Druid@Pemmin's Aura
+Twitching Doll@Freed from the Real
+Archon of Sun's Grace@Secret Arcade // Dusty Parlor
+Secret Arcade // Dusty Parlor@Gremlin Tamer
+Enchanted Evening@Gremlin Tamer
+Mind Over Matter@Chromatic Orrery
+Murderous Redcap@Gev, Scaled Scorch
+Anzrag, the Quake-Mole@Darksteel Mutation
+The Fifth Doctor@Adric, Mathematical Genius
+Aurelia, the Warleader@Gilraen, Dúnedain Protector
+Ghired, Mirror of the Wilds@Coercive Recruiter
+Ghired, Mirror of the Wilds@Battered Golem
+Ghired, Mirror of the Wilds@Steelfin Whale
+Ghired, Mirror of the Wilds@Sunstrike Legionnaire
+Ghired, Mirror of the Wilds@Grimgrin, Corpse-Born
+Touch the Spirit Realm@Starfield of Nyx
+Niv-Mizzet, Visionary@Niv-Mizzet, Parun
+Niv-Mizzet, Visionary@Niv-Mizzet, the Firemind
+Heartless Hidetsugu@Twinflame Tyrant
+Aphelia, Viper Whisperer@Bloodletter of Aclazotz
+Emiel the Blessed@Dionus, Elvish Archdruid
+Quilled Greatwurm@Sage of Hours
+Tayam, Luminous Enigma@Devoted Druid
+Dionus, Elvish Archdruid@Temur Sabertooth
+Mirror Room // Fractured Realm@Palinchron
+Orthion, Hero of Lavabrink@Great Oak Guardian
+The Mindskinner@Syr Konrad, the Grim
+Toralf, God of Fury // Toralf's Hammer@Blasphemous Act
+Cavern-Hoard Dragon@Aggravated Assault
+Aggravated Assault@Primal Adversary
+Kiki-Jiki, Mirror Breaker@Fear of Missing Out
+Tyvar, the Pummeler@Devoted Druid
+Shadow of the Second Sun@Aggravated Assault
+Heartless Hidetsugu@Fiendish Duo
+Aggravated Assault@Cryptolith Rite
+Fear of Missing Out@Splinter Twin
+Shilgengar, Sire of Famine@March of the Machines
+Shilgengar, Sire of Famine@Titania's Song
+Shilgengar, Sire of Famine@Displaced Dinosaurs
+Gremlin Tamer@Screams from Within
+Tombstone Stairwell@Poison-Tip Archer
+Tombstone Stairwell@Blood Artist
+Kiki-Jiki, Mirror Breaker@Hazel's Brewmaster
+Kodama of the East Tree@Chthonian Nightmare
+Doomsday Excruciator@Phenax, God of Deception
+Doomsday Excruciator@Breach the Multiverse
+Loot, the Pathfinder@Deadeye Navigator
+Aether Syphon@Peer into the Abyss
+Body of Research@Peema Trailblazer
+Soulfire Grand Master@Mana Geyser
+Amalia Benavides Aguirre@Wildgrowth Walker
+Riverchurn Monument@Cut Your Losses
+Dance of Many@Felidar Guardian
+Satya, Aetherflux Genius@Breath of Fury
+Sage of the Falls@Cryptcaller Chariot
+Intruder Alarm@Nemata, Grove Guardian
+The Gitrog Monster@Dakmor Salvage
+The Gitrog Monster@The Necrobloom
+Baylen, the Haymaker@Aggravated Assault
+Time Sieve@Luxurious Locomotive
+Hellkite Charger@Luxurious Locomotive
+Najeela, the Blade-Blossom@Luxurious Locomotive
+Aggravated Assault@Luxurious Locomotive
+Conqueror's Galleon // Conqueror's Foothold@Capture of Jingzhou
+Conqueror's Galleon // Conqueror's Foothold@Rude Awakening
+Conqueror's Galleon // Conqueror's Foothold@Reset
+Conqueror's Galleon // Conqueror's Foothold@Turnabout
+Tidal Control@Mindslaver
+Samut, the Driving Force@Sprout Swarm
+Haldir, Lórien Lieutenant@Devoted Druid
+Orthion, Hero of Lavabrink@Timestream Navigator
+Worldfire@Vela the Night-Clad
+Cryptcaller Chariot@Greater Good
+Jumbo Cactuar@Selvala, Heart of the Wilds
+Jumbo Cactuar@Ruthless Technomancer
+Jumbo Cactuar@Swords to Plowshares
+Jumbo Cactuar@Windswift Slice
+Jumbo Cactuar@Wall of Reverence
+Jumbo Cactuar@Bighorner Rancher
+Jumbo Cactuar@Infested Thrinax
+Jumbo Cactuar@Brightmare
+Jumbo Cactuar@Predator's Rapport
+Jumbo Cactuar@Dazzling Reflection
+Jumbo Cactuar@Peema Aether-Seer
+Jumbo Cactuar@Soul's Grace
+Jumbo Cactuar@Chastise
+Jumbo Cactuar@Altar of Dementia
+Jumbo Cactuar@Chandra's Ignition
+Redshift, Rocketeer Chief@Aggravated Assault
+Marvin, Murderous Mimic@Grinning Ignus
+Najeela, the Blade-Blossom@Selvala, Heart of the Wilds
+Aggravated Assault@Esika, God of the Tree // The Prismatic Bridge
+Astarion, the Decadent@Blood Tribute
+Nyxbloom Ancient@Rite of Replication
+Isengard Unleashed@Heartless Hidetsugu
+Shilgengar, Sire of Famine@Stridehangar Automaton
+Saheeli, Radiant Creator@Timestream Navigator
+Psychosis Crawler@Peer into the Abyss
+Sandstorm Crasher@Aurelia, the Warleader
+The Twelfth Doctor@Increasing Vengeance
+The Peregrine Dynamo@Plargg, Dean of Chaos // Augusta, Dean of Order
+Betor, Ancestor's Voice@Sage of Hours
+Betor, Kin to All@Bloodletter of Aclazotz
+Shorikai, Genesis Engine@Intruder Alarm
+Adaptive Training Post@Flare of Duplication
+Aetheric Amplifier@Teferi, Master of Time
+Aetheric Amplifier@Magistrate's Scepter
+Marina Vendrell's Grimoire@Feast of Sanity
+Marrow-Gnawer@Faces of the Past
+Kheru Goldkeeper@Tortured Existence
+Terisian Mindbreaker@Keening Stone
+Maddening Cacophony@Keening Stone
+Traumatize@Keening Stone
+Cut Your Losses@Keening Stone
+Lord Xander, the Collector@Keening Stone
+Fleet Swallower@Keening Stone
+Magmakin Artillerist@Curiosity
+Fortune Teller's Talent@Sensei's Divining Top
+Mardu Siegebreaker@Port Razer
+Kiki-Jiki, Mirror Breaker@Ratadrabik of Urborg
+Mikaeus, the Unhallowed@Canker Abomination
+Springheart Nantuko@Nissa, Who Shakes the World
+Phelddagrif@Intruder Alarm
+Questing Phelddagrif@Intruder Alarm
+Necrotic Ooze@Mirror-Mad Phantasm
+Tidespout Tyrant@Grim Monolith
+Lazav, the Multifarious@Mirror-Mad Phantasm
+The Scarab God@Mirror-Mad Phantasm
+Mairsil, the Pretender@Mirror-Mad Phantasm
+Araumi of the Dead Tide@Mirror-Mad Phantasm
+Mirror-Mad Phantasm@Blade of Selves
+Mirror-Mad Phantasm@Legion Loyalty
+Ludevic, Necrogenius // Olag, Ludevic's Hubris@Mirror-Mad Phantasm
+Dance of Many@Mirror-Mad Phantasm
+Metamorphic Alteration@Mirror-Mad Phantasm
+Anzrag, the Quake-Mole@Anzrag, the Quake-Mole
+Patchwork Crawler@Mirror-Mad Phantasm
+Mirror-Mad Phantasm@See Double
+Chancellor of the Spires@Displacer Kitten
+Ancient Copper Dragon@Aggravated Assault
+Sway of the Stars@Syr Konrad, the Grim
+Sway of the Stars@Vela the Night-Clad
+Sway of the Stars@Nadier's Nightblade
+Sway of the Stars@Zurgo Stormrender
+Felothar the Steadfast@Body of Research
+Blazing Sunsteel@The Mycosynth Gardens
+Robaran Mercenaries@Ioreth of the Healing House
+Demonic Consultation@Timestream Navigator
+Soulfire Grand Master@Star of Extinction
+Soulfire Grand Master@Blasphemous Act
+Cloud, Planet's Champion@Crackdown Construct
+Yuna, Grand Summoner@Freed from the Real
+Jaws of Defeat@Viscid Lemures
+Repercussion@Fear of Burning Alive
+Kefka, Court Mage // Kefka, Ruler of Ruin@Queza, Augur of Agonies
+Kefka, Court Mage // Kefka, Ruler of Ruin@Starving Revenant
+Terra, Magical Adept // Esper Terra@Spark Double
+Vivi Ornitier@Deadeye Navigator
+Vivi Ornitier@Emiel the Blessed
+Kefka, Court Mage // Kefka, Ruler of Ruin@Psychosis Crawler
+Maester Seymour@Sage of Hours
+General Leo Cristophe@Flesh Duplicate
+Vivi Ornitier@Quicksilver Elemental
+Kefka, Court Mage // Kefka, Ruler of Ruin@Glint-Horn Buccaneer
+Kefka, Court Mage // Kefka, Ruler of Ruin@Feast of Sanity
+Protean Thaumaturge@Ondu Spiritdancer
+Kefka, Court Mage // Kefka, Ruler of Ruin@Niv-Mizzet, the Firemind
+Kefka, Court Mage // Kefka, Ruler of Ruin@Niv-Mizzet, Parun
+Spellbinder@Great Train Heist
+Terra, Magical Adept // Esper Terra@The Apprentice's Folly
+Sharuum the Hegemon@Hashaton, Scarab's Fist
+Mardu Siegebreaker@Éomer, Marshal of Rohan
+Overkill@Jaws of Defeat
+Gogo, Master of Mimicry@Magosi, the Waterveil
+Gogo, Master of Mimicry@Magistrate's Scepter
+Timestream Navigator@The Fire Crystal
+Jenova, Ancient Calamity@Sage of Hours
+Hyalopterous Lemure@Jaws of Defeat
+Mardu Siegebreaker@Felidar Guardian
+Cephalid Aristocrat@Grafted Wargear
+Cephalid Aristocrat@Lightning Greaves
+Satoru Umezawa@Intruder Alarm
+Dissection Tools@One with the Kami
diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt
index 696ad31ba28..d7858933b16 100644
--- a/Mage/src/main/resources/tokens-database.txt
+++ b/Mage/src/main/resources/tokens-database.txt
@@ -2253,6 +2253,7 @@
|Generate|TOK:WHO|Human|2||TheEleventhHourToken|
|Generate|TOK:WHO|Human Noble|||TheGirlInTheFireplaceHumanNobleToken|
|Generate|TOK:WHO|Mark of the Rani|||MarkOfTheRaniToken|
+|Generate|TOK:WHO|Mutant|||Mutant33DeathtouchToken|
|Generate|TOK:WHO|Soldier|||SoldierToken|
|Generate|TOK:WHO|Treasure|1||TreasureToken|
|Generate|TOK:WHO|Treasure|2||TreasureToken|
diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt
index ba9c72b27a8..21675cca7f4 100644
--- a/Utils/mtg-cards-data.txt
+++ b/Utils/mtg-cards-data.txt
@@ -53980,282 +53980,424 @@ Jukai Liberator|Alchemy: Kamigawa|27|R|{2}{G}|Creature - Snake Ninja|3|3|Ninjuts
Runaway Growth|Alchemy: Kamigawa|28|R|{3}{G}|Enchantment - Aura|||Starting intensity 1$Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional amount of {G} equal to Runaway Growth's intensity. Then Runaway Growth intensifies by 1.|
Forceful Cultivator|Alchemy: Kamigawa|29|M|{2}{G}{G}|Creature - Snake Shaman|2|3|This spell costs {2} less to cast if there are no land cards in your hand.$When Forceful Cultivator enters the battlefield, search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.|
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 Acrobatic Cheerleader 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, Cult Healer gains lifelink until end of turn.|
-Dazzling Theater // Prop Room|Duskmourn: House of Horror|3|R|{3}{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.)$Creature spells you cast have convoke.$Prop Room${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.)$Untap each creature you control during each other player's untap step.|
-Dollmaker's Shop // Porcelain Gallery|Duskmourn: House of Horror|4|M|{1}{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 one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.$Porcelain Gallery${4}{W}{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.)$Creatures you control have base power and toughness each equal to the number of creatures you control.|
+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.)|
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.|
Exorcise|Duskmourn: House of Horror|8|U|{1}{W}|Sorcery|||Exile target artifact, enchantment, or creature with power 4 or greater.|
-Fear of Abduction|Duskmourn: House of Horror|9|U|{4}{W}{W}|Enchantment Creature - Nightmare|5|5|As an additional cost to cast this spell, exile a creature you control.$Flying$When Fear of Abduction enters, exile target creature an opponent controls.$When Fear of Abduction leaves the battlefield, put each card exiled with it into its owner's hand.|
-Fear of Immobility|Duskmourn: House of Horror|10|C|{4}{W}|Enchantment Creature - Nightmare|4|4|When Fear of Immobility enters, tap up to one target creature. If an opponent controls that creature, put a stun counter on it.|
-Fear of Surveillance|Duskmourn: House of Horror|11|C|{1}{W}|Enchantment Creature - Nightmare|2|2|Vigilance$Whenever Fear of Surveillance attacks, surveil 1.|
-Friendly Ghost|Duskmourn: House of Horror|12|C|{3}{W}|Creature - Spirit|2|4|Flying$When Friendly Ghost 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 Ghostly Dancers 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 Glimmer Seeker 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|||(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 a 1/1 white Glimmer enchantment creature token.$Elegant Rotunda${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.)$When you unlock this door, put a +1/+1 counter on each of up to two target creatures.|
-Hardened Escort|Duskmourn: House of Horror|16|C|{2}{W}|Creature - Human Soldier|2|4|Whenever Hardened Escort attacks, another target creature you control gets +1/+0 and gains indestructible until end of turn.|
+Fear of Abduction|Duskmourn: House of Horror|9|U|{4}{W}{W}|Enchantment Creature - Nightmare|5|5|As an additional cost to cast this spell, exile a creature you control.$Flying$When this creature enters, exile target creature an opponent controls.$When this creature leaves the battlefield, put each card exiled with it into its owner's hand.|
+Fear of Immobility|Duskmourn: House of Horror|10|C|{4}{W}|Enchantment Creature - Nightmare|4|4|When this creature enters, tap up to one target creature. If an opponent controls that creature, put a stun counter on it.|
+Fear of Surveillance|Duskmourn: House of Horror|11|C|{1}{W}|Enchantment Creature - Nightmare|2|2|Vigilance$Whenever this creature attacks, surveil 1.|
+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.)|
+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 Leyline of Hope 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.|
+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.|
Lionheart Glimmer|Duskmourn: House of Horror|19|U|{3}{W}{W}|Enchantment Creature - Cat Glimmer|2|5|Ward {2}$Whenever you attack, creatures you control get +1/+1 until end of turn.|
-Living Phone|Duskmourn: House of Horror|20|C|{2}{W}|Artifact Creature - Toy|2|1|When Living Phone dies, look at the top five cards of your library. You may reveal a creature card with power 2 or less from among them and put it into your hand. Put the rest on the bottom of your library in a random order.|
+Living Phone|Duskmourn: House of Horror|20|C|{2}{W}|Artifact Creature - Toy|2|1|When this creature dies, look at the top five cards of your library. You may reveal a creature card with power 2 or less from among them and put it into your hand. Put the rest on the bottom of your library in a random order.|
Optimistic Scavenger|Duskmourn: House of Horror|21|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.|
-Orphans of the Wheat|Duskmourn: House of Horror|22|U|{1}{W}|Creature - Human|2|1|Whenever Orphans of the Wheat attacks, tap any number of untapped creatures you control. Orphans of the Wheat gets +1/+1 until end of turn for each creature tapped this way.|
-Overlord of the Mistmoors|Duskmourn: House of Horror|23|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever Overlord of the Mistmoors enters or attacks, create two 2/1 white Insect creature tokens with flying.|
-Patched Plaything|Duskmourn: House of Horror|24|U|{2}{W}|Artifact Creature - Toy|4|3|Double strike$Patched Plaything enters with two -1/-1 counters on it if you cast it from your hand.|
-Possessed Goat|Duskmourn: House of Horror|25|C|{W}|Creature - Goat|1|1|{3}, Discard a card: Put three +1/+1 counters on Possessed Goat and it becomes a black Demon in addition to its other colors and types. Activate only once.|
-Reluctant Role Model|Duskmourn: House of Horror|26|R|{1}{W}|Creature - Human Survivor|2|2|Survival -- At the beginning of your second main phase, if Reluctant Role Model is tapped, put a flying, lifelink, or +1/+1 counter on it.$Whenever Reluctant Role Model or another creature you control dies, if it had counters on it, put those counters on up to one target creature.|
-Savior of the Small|Duskmourn: House of Horror|27|U|{3}{W}|Creature - Kor Survivor|3|4|Survival -- At the beginning of your second main phase, if Savior of the Small is tapped, return target creature card with mana value 3 or less from your graveyard to your hand.|
+Orphans of the Wheat|Duskmourn: House of Horror|22|U|{1}{W}|Creature - Human|2|1|Whenever this creature attacks, tap any number of untapped creatures you control. This creature gets +1/+1 until end of turn for each creature tapped this way.|
+Overlord of the Mistmoors|Duskmourn: House of Horror|23|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever this permanent enters or attacks, create two 2/1 white Insect creature tokens with flying.|
+Patched Plaything|Duskmourn: House of Horror|24|U|{2}{W}|Artifact Creature - Toy|4|3|Double strike$This creature enters with two -1/-1 counters on it if you cast it from your hand.|
+Possessed Goat|Duskmourn: House of Horror|25|C|{W}|Creature - Goat|1|1|{3}, Discard a card: Put three +1/+1 counters on this creature and it becomes a black Demon in addition to its other colors and types. Activate only once.|
+Reluctant Role Model|Duskmourn: House of Horror|26|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.|
+Savior of the Small|Duskmourn: House of Horror|27|U|{3}{W}|Creature - Kor Survivor|3|4|Survival -- At the beginning of your second main phase, if this creature is tapped, return target creature card with mana value 3 or less from your graveyard to your hand.|
Seized from Slumber|Duskmourn: House of Horror|28|C|{4}{W}|Instant|||This spell costs {3} less to cast if it targets a tapped creature.$Destroy target creature.|
-Shardmage's Rescue|Duskmourn: House of Horror|29|U|{W}|Enchantment - Aura|||Flash$Enchant creature you control$As long as Shardmage's Rescue entered this turn, enchanted creature has hexproof.$Enchanted creature gets +1/+1.|
-Sheltered by Ghosts|Duskmourn: House of Horror|30|U|{1}{W}|Enchantment - Aura|||Enchant creature you control$When Sheltered by Ghosts enters, exile target nonland permanent an opponent controls until Sheltered by Ghosts leaves the battlefield.$Enchanted creature gets +1/+0 and has lifelink and ward {2}.|
+Shardmage's Rescue|Duskmourn: House of Horror|29|U|{W}|Enchantment - Aura|||Flash$Enchant creature you control$As long as this Aura entered this turn, enchanted creature has hexproof.$Enchanted creature gets +1/+1.|
+Sheltered by Ghosts|Duskmourn: House of Horror|30|U|{1}{W}|Enchantment - Aura|||Enchant creature you control$When this Aura enters, exile target nonland permanent an opponent controls until this Aura leaves the battlefield.$Enchanted creature gets +1/+0 and has lifelink and ward {2}.|
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 Splitskin Doll 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|||(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, return target creature card with mana value 3 or less from your graveyard to the battlefield.$Hospital Room${3}{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 attack, put a +1/+1 counter on target attacking creature.|
-Toby, Beastie Befriender|Duskmourn: House of Horror|35|R|{2}{W}|Legendary Creature - Human Wizard|1|1|When Toby, Beastie Befriender enters, create a 4/4 white Beast creature token with "This creature 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 Trapped in the Screen enters, exile target artifact, creature, or enchantment an opponent controls until Trapped in the Screen leaves the battlefield.|
-Unidentified Hovership|Duskmourn: House of Horror|37|R|{1}{W}{W}|Artifact - Vehicle|2|2|Flying$When Unidentified Hovership enters, exile up to one target creature with toughness 5 or less.$When Unidentified Hovership leaves the battlefield, the exiled card's owner manifests dread.$Crew 1|
-Unsettling Twins|Duskmourn: House of Horror|38|C|{3}{W}|Creature - Human|2|2|When Unsettling Twins enters, manifest dread.|
+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.)|
+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|
+Unsettling Twins|Duskmourn: House of Horror|38|C|{3}{W}|Creature - Human|2|2|When this creature enters, manifest dread.|
Unwanted Remake|Duskmourn: House of Horror|39|U|{W}|Instant|||Destroy target creature. Its controller manifests dread.|
-Veteran Survivor|Duskmourn: House of Horror|40|U|{W}|Creature - Human Survivor|2|1|Survival -- At the beginning of your second main phase, if Veteran Survivor is tapped, exile up to one target card from a graveyard.$As long as there are three or more cards exiled with Veteran Survivor, it gets +3/+3 and has hexproof.|
+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|||(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, return up to one target creature to its owner's hand.$Locker Room${4}{U}$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 creatures you control deal combat damage to a player, draw a card.|
-Central Elevator // Promising Stairs|Duskmourn: House of Horror|44|R|{3}{U}|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, 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.$Promising Stairs${2}{U}$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.)$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.|
-Clammy Prowler|Duskmourn: House of Horror|45|C|{3}{U}|Enchantment Creature - Horror|2|5|Whenever Clammy Prowler attacks, another target attacking creature can't be blocked this turn.|
+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.)|
+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 Cursed Windbreaker enters, manifest dread, then attach Cursed Windbreaker to that creature.$Equipped creature has flying.$Equip {3}|
+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}|
Daggermaw Megalodon|Duskmourn: House of Horror|48|C|{4}{U}{U}|Creature - Shark|5|7|Vigilance$Islandcycling {2}|
Don't Make a Sound|Duskmourn: House of Horror|49|C|{1}{U}|Instant|||Counter target spell unless its controller pays {2}. If they do, surveil 2.|
Duskmourn's Domination|Duskmourn: House of Horror|50|U|{4}{U}{U}|Enchantment - Aura|||Enchant creature$You control enchanted creature.$Enchanted creature gets -3/-0 and loses all abilities.|
Enduring Curiosity|Duskmourn: House of Horror|51|R|{2}{U}{U}|Enchantment Creature - Cat Glimmer|4|3|Flash$Whenever a creature you control deals combat damage to a player, draw a card.$When Enduring Curiosity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
Enter the Enigma|Duskmourn: House of Horror|52|C|{U}|Sorcery|||Target creature can't be blocked this turn.$Draw a card.|
Entity Tracker|Duskmourn: House of Horror|53|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.|
-Erratic Apparition|Duskmourn: House of Horror|54|C|{2}{U}|Creature - Spirit|1|3|Flying, vigilance$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, Erratic Apparition gets +1/+1 until end of turn.|
-Fear of Failed Tests|Duskmourn: House of Horror|55|U|{4}{U}|Enchantment Creature - Nightmare|2|7|Whenever Fear of Failed Tests deals combat damage to a player, draw that many cards.|
-Fear of Falling|Duskmourn: House of Horror|56|U|{3}{U}{U}|Enchantment Creature - Nightmare|4|4|Flying$Whenever Fear of Falling attacks, target creature defending player controls gets -2/-0 and loses flying until your next turn.|
-Fear of Impostors|Duskmourn: House of Horror|57|U|{1}{U}{U}|Enchantment Creature - Nightmare|3|2|Flash$When Fear of Impostors enters, counter target spell. Its controller manifests dread.|
+Erratic Apparition|Duskmourn: House of Horror|54|C|{2}{U}|Creature - Spirit|1|3|Flying, vigilance$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, this creature gets +1/+1 until end of turn.|
+Fear of Failed Tests|Duskmourn: House of Horror|55|U|{4}{U}|Enchantment Creature - Nightmare|2|7|Whenever this creature deals combat damage to a player, draw that many cards.|
+Fear of Falling|Duskmourn: House of Horror|56|U|{3}{U}{U}|Enchantment Creature - Nightmare|4|4|Flying$Whenever this creature attacks, target creature defending player controls gets -2/-0 and loses flying until your next turn.|
+Fear of Impostors|Duskmourn: House of Horror|57|U|{1}{U}{U}|Enchantment Creature - Nightmare|3|2|Flash$When this creature enters, counter target spell. Its controller manifests dread.|
Fear of Isolation|Duskmourn: House of Horror|58|U|{1}{U}|Enchantment Creature - Nightmare|2|3|As an additional cost to cast this spell, return a permanent you control to its owner's hand.$Flying|
-Floodpits Drowner|Duskmourn: House of Horror|59|U|{1}{U}|Creature - Merfolk|2|1|Flash$Vigilance$When Floodpits Drowner enters, tap target creature an opponent controls and put a stun counter on it.${1}{U}, {T}: Shuffle Floodpits Drowner and target creature with a stun counter on it into their owners' libraries.|
+Floodpits Drowner|Duskmourn: House of Horror|59|U|{1}{U}|Creature - Merfolk|2|1|Flash$Vigilance$When this creature enters, tap target creature an opponent controls and put a stun counter on it.${1}{U}, {T}: Shuffle this creature and target creature with a stun counter on it into their owners' libraries.|
Get Out|Duskmourn: House of Horror|60|U|{U}{U}|Instant|||Choose one --$* Counter target creature or enchantment spell.$* Return one or two target creatures and/or enchantments you own to your hand.|
-Ghostly Keybearer|Duskmourn: House of Horror|61|U|{3}{U}|Creature - Spirit|3|3|Flying$Whenever Ghostly Keybearer deals combat damage to a player, unlock a locked door of up to one target Room you control.|
+Ghostly Keybearer|Duskmourn: House of Horror|61|U|{3}{U}|Creature - Spirit|3|3|Flying$Whenever this creature deals combat damage to a player, unlock a locked door of up to one target Room you control.|
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 Leyline of Transformation is in your opening hand, you may begin the game with it on the battlefield.$As Leyline of Transformation 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.|
+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|||(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, tap up to one target creature and put two stun counters on it.$Drowned Diner${3}{U}{U}$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, draw three cards, then discard a card.|
+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.)|
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|||(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 a token that's a copy of target creature you control, except it's a Reflection in addition to its other creature types.$Fractured Realm${5}{U}{U}$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 triggered ability of a permanent you control triggers, that ability triggers an additional time.|
-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 Overlord of the Floodpits enters or attacks, draw two cards, then discard a card.|
+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.)|
+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$Piranha Fly enters tapped.|
+Piranha Fly|Duskmourn: House of Horror|70|C|{1}{U}|Creature - Fish Insect|2|1|Flying$This creature enters tapped.|
Scrabbling Skullcrab|Duskmourn: House of Horror|71|U|{U}|Creature - Crab Skeleton|0|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, target player mills two cards.|
-Silent Hallcreeper|Duskmourn: House of Horror|72|R|{1}{U}|Enchantment Creature - Horror|1|1|Silent Hallcreeper can't be blocked.$Whenever Silent Hallcreeper deals combat damage to a player, choose one that hasn't been chosen --$* Put two +1/+1 counters on Silent Hallcreeper.$* Draw a card.$* Silent Hallcreeper becomes a copy of another target creature you control.|
-Stalked Researcher|Duskmourn: House of Horror|73|C|{1}{U}|Creature - Human Wizard|3|3|Defender$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, Stalked Researcher can attack this turn as though it didn't have defender.|
-Stay Hidden, Stay Silent|Duskmourn: House of Horror|74|U|{1}{U}|Enchantment - Aura|||Enchant creature$When Stay Hidden, Stay Silent enters, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.${4}{U}{U}: Shuffle enchanted creature into its owner's library, then manifest dread. Activate only as a sorcery.|
+Silent Hallcreeper|Duskmourn: House of Horror|72|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.|
+Stalked Researcher|Duskmourn: House of Horror|73|C|{1}{U}|Creature - Human Wizard|3|3|Defender$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, this creature can attack this turn as though it didn't have defender.|
+Stay Hidden, Stay Silent|Duskmourn: House of Horror|74|U|{1}{U}|Enchantment - Aura|||Enchant creature$When this Aura enters, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.${4}{U}{U}: Shuffle enchanted creature into its owner's library, then manifest dread. Activate only as a sorcery.|
The Tale of Tamiyo|Duskmourn: House of Horror|75|R|{2}{U}|Legendary Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after IV.)$I, II, III -- Mill two cards. If two cards that share a card type were milled this way, draw a card and repeat this process.$IV -- Exile any number of target instant, sorcery, and/or Tamiyo planeswalker cards from your graveyard. Copy them. You may cast any number of the copies.|
-Tunnel Surveyor|Duskmourn: House of Horror|76|C|{2}{U}|Creature - Human Detective|2|2|When Tunnel Surveyor enters, create a 1/1 white Glimmer enchantment creature token.|
+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|||(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, surveil 2.$Slimy Aquarium${3}{U}$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 a +1/+1 counter on that creature.|
+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.)|
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 Unwilling Vessel.$When Unwilling Vessel dies, create an X/X blue Spirit creature token with flying, where X is the number of counters on Unwilling Vessel.|
-Vanish from Sight|Duskmourn: House of Horror|82|C|{3}{U}|Instant|||Target nonland permanent's owner puts it on the top or bottom of their library. Surveil 1.|
-Appendage Amalgam|Duskmourn: House of Horror|83|C|{2}{B}|Enchantment Creature - Horror|3|2|Flash$Whenever Appendage Amalgam attacks, surveil 1.|
+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.|
+Appendage Amalgam|Duskmourn: House of Horror|83|C|{2}{B}|Enchantment Creature - Horror|3|2|Flash$Whenever this creature attacks, surveil 1.|
Balemurk Leech|Duskmourn: House of Horror|84|C|{1}{B}|Creature - Leech|2|2|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, each opponent loses 1 life.|
-Cackling Slasher|Duskmourn: House of Horror|85|C|{3}{B}|Creature - Human Assassin|3|3|Deathtouch$Cackling Slasher enters with a +1/+1 counter on it if a creature died this turn.|
+Cackling Slasher|Duskmourn: House of Horror|85|C|{3}{B}|Creature - Human Assassin|3|3|Deathtouch$This creature enters with a +1/+1 counter on it if a creature died this turn.|
Come Back Wrong|Duskmourn: House of Horror|86|R|{2}{B}|Sorcery|||Destroy target creature. If a creature card is put into a graveyard this way, return it to the battlefield under your control. Sacrifice it at the beginning of your next end step.|
Commune with Evil|Duskmourn: House of Horror|87|U|{2}{B}|Sorcery|||Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. You gain 3 life.|
-Cracked Skull|Duskmourn: House of Horror|88|C|{2}{B}|Enchantment - Aura|||Enchant creature$When Cracked Skull 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|Cynical Loner can't be blocked by Glimmers.$Survival -- At the beginning of your second main phase, if Cynical Loner 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, Dashing Bloodsucker gets +2/+0 and gains lifelink until end of turn.|
-Defiled Crypt // Cadaver Lab|Duskmourn: House of Horror|91|U|{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.)$Whenever one or more cards leave your graveyard, create a 2/2 black Horror enchantment creature token. This ability triggers only once each turn.$Cadaver Lab${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, return target creature card from your graveyard to your hand.|
+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.)|
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|||(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, you draw two cards and you lose 2 life.$Widow's Walk${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.)$Whenever a creature you control attacks alone, it gets +1/+0 and gains deathtouch until end of turn.|
-Doomsday Excruciator|Duskmourn: House of Horror|94|R|{B}{B}{B}{B}{B}{B}|Creature - Demon|6|6|Flying$When Doomsday Excruciator 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.|
+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.)|
+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 Fanatic of the Harrowing 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 Fear of Lost Teeth 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 Fear of the Dark attacks, if defending player controls no Glimmer creatures, it gains menace and deathtouch until end of turn.|
+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|||(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 dies, each opponent loses 1 life and you gain 1 life.$Awakening Hall${6}{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.)$When you unlock this door, return all creature cards from your graveyard to the battlefield.|
+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.)|
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 Innocuous Rat dies, manifest dread.|
-Killer's Mask|Duskmourn: House of Horror|104|U|{2}{B}|Artifact - Equipment|||When Killer's Mask enters, manifest dread, then attach Killer's Mask to that creature.$Equipped creature has menace.$Equip {2}|
+Innocuous Rat|Duskmourn: House of Horror|103|C|{1}{B}|Creature - Rat|1|1|When this creature dies, manifest dread.|
+Killer's Mask|Duskmourn: House of Horror|104|U|{2}{B}|Artifact - Equipment|||When this Equipment enters, manifest dread, then attach this Equipment to that creature.$Equipped creature has menace.$Equip {2}|
Let's Play a Game|Duskmourn: House of Horror|105|U|{3}{B}|Sorcery|||Delirium -- Choose one. If there are four or more card types among cards in your graveyard, choose one or more instead.$* Creatures your opponents control get -1/-1 until end of turn.$* Each opponent discards two cards.$* Each opponent loses 3 life and you gain 3 life.|
-Leyline of the Void|Duskmourn: House of Horror|106|R|{2}{B}{B}|Enchantment|||If Leyline of the Void is in your opening hand, you may begin the game with it on the battlefield.$If a card would be put into an opponent's graveyard from anywhere, exile it instead.|
+Leyline of the Void|Duskmourn: House of Horror|106|R|{2}{B}{B}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$If a card would be put into an opponent's graveyard from anywhere, exile it instead.|
Live or Die|Duskmourn: House of Horror|107|U|{3}{B}{B}|Instant|||Choose one --$* Return target creature card from your graveyard to the battlefield.$* Destroy target creature.|
-Meathook Massacre II|Duskmourn: House of Horror|108|M|{X}{X}{B}{B}{B}{B}|Legendary Enchantment|||When Meathook Massacre II enters, each player sacrifices X creatures.$Whenever a creature you control dies, you may pay 3 life. If you do, return that card under your control with a finality counter on it.$Whenever a creature an opponent controls dies, they may pay 3 life. If they don't, return that card under your control with a finality counter on it.|
-Miasma Demon|Duskmourn: House of Horror|109|U|{4}{B}{B}|Creature - Demon|5|4|Flying$When Miasma Demon enters, you may discard any number of cards. When you do, up to that many target creatures each get -2/-2 until end of turn.|
+Meathook Massacre II|Duskmourn: House of Horror|108|M|{X}{X}{B}{B}{B}{B}|Legendary Enchantment|||When Meathook Massacre II enters, each player sacrifices X creatures of their choice.$Whenever a creature you control dies, you may pay 3 life. If you do, return that card under your control with a finality counter on it.$Whenever a creature an opponent controls dies, they may pay 3 life. If they don't, return that card under your control with a finality counter on it.|
+Miasma Demon|Duskmourn: House of Horror|109|U|{4}{B}{B}|Creature - Demon|5|4|Flying$When this creature enters, you may discard any number of cards. When you do, up to that many target creatures each get -2/-2 until end of turn.|
Murder|Duskmourn: House of Horror|110|C|{1}{B}{B}|Instant|||Destroy target creature.|
-Nowhere to Run|Duskmourn: House of Horror|111|U|{1}{B}|Enchantment|||Flash$When Nowhere to Run enters, target creature an opponent controls gets -3/-3 until end of turn.$Creatures your opponents control can be the targets of spells and abilities as though they didn't have hexproof. Ward abilities of those creatures don't trigger.|
-Osseous Sticktwister|Duskmourn: House of Horror|112|U|{1}{B}|Artifact Creature - Scarecrow|2|2|Lifelink$Delirium -- At the beginning of your end step, if there are four or more card types among cards in your graveyard, each opponent may sacrifice a nonland permanent or discard a card. Then Osseous Sticktwister deals damage equal to its power to each opponent who didn't sacrifice a permanent or discard a card this way.|
-Overlord of the Balemurk|Duskmourn: House of Horror|113|M|{3}{B}{B}|Enchantment Creature - Avatar Horror|5|5|Impending 5--{1}{B}$Whenever Overlord of the Balemurk enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.|
-Popular Egotist|Duskmourn: House of Horror|114|U|{2}{B}|Creature - Human Rogue|3|2|{1}{B}, Sacrifice another creature or enchantment: Popular Egotist gains indestructible until end of turn. Tap it.$Whenever you sacrifice a permanent, target opponent loses 1 life and you gain 1 life.|
-Resurrected Cultist|Duskmourn: House of Horror|115|C|{2}{B}|Creature - Human Cleric|4|1|Delirium -- {2}{B}{B}: Return Resurrected Cultist 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.|
+Nowhere to Run|Duskmourn: House of Horror|111|U|{1}{B}|Enchantment|||Flash$When this enchantment enters, target creature an opponent controls gets -3/-3 until end of turn.$Creatures your opponents control can be the targets of spells and abilities as though they didn't have hexproof. Ward abilities of those creatures don't trigger.|
+Osseous Sticktwister|Duskmourn: House of Horror|112|U|{1}{B}|Artifact Creature - Scarecrow|2|2|Lifelink$Delirium -- At the beginning of your end step, if there are four or more card types among cards in your graveyard, each opponent may sacrifice a nonland permanent of their choice or discard a card. Then this creature deals damage equal to its power to each opponent who didn't sacrifice a permanent or discard a card this way.|
+Overlord of the Balemurk|Duskmourn: House of Horror|113|M|{3}{B}{B}|Enchantment Creature - Avatar Horror|5|5|Impending 5--{1}{B}$Whenever this permanent enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.|
+Popular Egotist|Duskmourn: House of Horror|114|U|{2}{B}|Creature - Human Rogue|3|2|{1}{B}, Sacrifice another creature or enchantment: This creature gains indestructible until end of turn. Tap it.$Whenever you sacrifice a permanent, target opponent loses 1 life and you gain 1 life.|
+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 Sporogenic Infection enters, target player sacrifices a creature 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|||(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.)$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.$Ritual Chamber${3}{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.)$When you unlock this door, create a 6/6 black Demon creature token with flying.|
-Unstoppable Slasher|Duskmourn: House of Horror|119|R|{2}{B}|Creature - Zombie Assassin|2|3|Deathtouch$Whenever Unstoppable Slasher deals combat damage to a player, they lose half their life, rounded up.$When Unstoppable Slasher 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.|
+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.)|
+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 Valgavoth's Faithful: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery.|
-Vile Mutilator|Duskmourn: House of Horror|122|U|{5}{B}{B}|Creature - Demon|6|5|As an additional cost to cast this spell, sacrifice a creature or enchantment.$Flying, trample$When Vile Mutilator enters, each opponent sacrifices a nontoken enchantment, then sacrifices a nontoken creature.|
+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.|
+Vile Mutilator|Duskmourn: House of Horror|122|U|{5}{B}{B}|Creature - Demon|6|5|As an additional cost to cast this spell, sacrifice a creature or enchantment.$Flying, trample$When this creature enters, each opponent sacrifices a nontoken enchantment of their choice, then sacrifices a nontoken creature of their choice.|
Winter's Intervention|Duskmourn: House of Horror|123|C|{1}{B}|Instant|||Winter's Intervention deals 2 damage to target creature. You gain 2 life.|
Withering Torment|Duskmourn: House of Horror|124|U|{2}{B}|Instant|||Destroy target creature or enchantment. You lose 2 life.|
Bedhead Beastie|Duskmourn: House of Horror|125|C|{4}{R}{R}|Creature - Beast|5|6|Menace$Mountaincycling {2}|
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 Boilerbilges Ripper enters, you may sacrifice another creature or enchantment. When you do, Boilerbilges Ripper deals 2 damage to any target.|
-Chainsaw|Duskmourn: House of Horror|128|R|{1}{R}|Artifact - Equipment|||When Chainsaw enters, it deals 3 damage to up to one target creature.$Whenever one or more creatures die, put a rev counter on Chainsaw.$Equipped creature gets +X/+0, where X is the number of rev counters on Chainsaw.$Equip {3}|
-Charred Foyer // Warped Space|Duskmourn: House of Horror|129|M|{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.)$At the beginning of your upkeep, exile the top card of your library. You may play that card this turn.$Warped Space${4}{R}{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.)$Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast from exile.|
-Clockwork Percussionist|Duskmourn: House of Horror|130|C|{R}|Artifact Creature - Monkey Toy|1|1|Haste$When Clockwork Percussionist 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 Cursed Recording. 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.|
+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.)|
+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.|
Enduring Courage|Duskmourn: House of Horror|133|R|{2}{R}{R}|Enchantment Creature - Dog Glimmer|3|3|Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn.$When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
-Fear of Being Hunted|Duskmourn: House of Horror|134|U|{1}{R}{R}|Enchantment Creature - Nightmare|4|2|Haste$Fear of Being Hunted must be blocked if able.|
-Fear of Burning Alive|Duskmourn: House of Horror|135|U|{4}{R}{R}|Enchantment Creature - Nightmare|4|4|When Fear of Burning Alive 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, Fear of Burning Alive 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 Fear of Missing Out enters, discard a card, then draw a card.$Delirium -- Whenever Fear of Missing Out 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|||(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 4 damage to target creature an opponent controls.$Shattered Yard${4}{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.)$At the beginning of your end step, this Room deals 1 damage to each opponent.|
+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.)|
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 Hand That Feeds 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.|
+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.|
-Infernal Phantom|Duskmourn: House of Horror|141|U|{3}{R}|Creature - Spirit|2|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, Infernal Phantom gets +2/+0 until end of turn.$When Infernal Phantom dies, it deals damage equal to its power to any target.|
+Infernal Phantom|Duskmourn: House of Horror|141|U|{3}{R}|Creature - Spirit|2|3|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, this creature gets +2/+0 until end of turn.$When this creature dies, it deals damage equal to its power to any target.|
Irreverent Gremlin|Duskmourn: House of Horror|142|U|{1}{R}|Creature - Gremlin|2|2|Menace$Whenever another creature you control with power 2 or less enters, you may discard a card. If you do, draw a card. Do this only once each turn.|
-Leyline of Resonance|Duskmourn: House of Horror|143|R|{2}{R}{R}|Enchantment|||If Leyline of Resonance is in your opening hand, you may begin the game with it on the battlefield.$Whenever you cast an instant or sorcery spell that targets only a single creature you control, copy that spell. You may choose new targets for the copy.|
+A-Leyline of Resonance|Duskmourn: House of Horror|A-143|R|{2}{R}{R}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$Whenever you cast an instant or sorcery spell that targets only a single creature you control, you may pay {1}. If you do, copy that spell. You may choose new targets for the copy.|
+Leyline of Resonance|Duskmourn: House of Horror|143|R|{2}{R}{R}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$Whenever you cast an instant or sorcery spell that targets only a single creature you control, copy that spell. You may choose new targets for the copy.|
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, Swift Survivalist 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 Overlord of the Boilerbilges 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|||(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, exile the top two cards of your library. You may play them until the end of your next turn.$Defaced Gallery${1}{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.)$Whenever you attack, attacking creatures you control get +1/+0 until end of turn.|
-Piggy Bank|Duskmourn: House of Horror|148|U|{1}{R}|Artifact Creature - Boar Toy|3|2|When Piggy Bank dies, create a Treasure token.|
+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.)|
+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.|
-Rampaging Soulrager|Duskmourn: House of Horror|151|C|{2}{R}|Creature - Spirit|1|4|Rampaging Soulrager gets +3/+0 as long as there are two or more unlocked doors among Rooms you control.|
+Rampaging Soulrager|Duskmourn: House of Horror|151|C|{2}{R}|Creature - Spirit|1|4|This creature gets +3/+0 as long as there are two or more unlocked doors among Rooms you control.|
Razorkin Hordecaller|Duskmourn: House of Horror|152|U|{4}{R}|Creature - Human Clown Berserker|4|4|Haste$Whenever you attack, create a 1/1 red Gremlin creature token.|
-Razorkin Needlehead|Duskmourn: House of Horror|153|R|{R}{R}|Creature - Human Assassin|2|2|Razorkin Needlehead has first strike during your turn.$Whenever an opponent draws a card, Razorkin Needlehead deals 1 damage to them.|
+Razorkin Needlehead|Duskmourn: House of Horror|153|R|{R}{R}|Creature - Human Assassin|2|2|This creature has first strike during your turn.$Whenever an opponent draws a card, this creature deals 1 damage to them.|
Ripchain Razorkin|Duskmourn: House of Horror|154|C|{3}{R}|Creature - Human Berserker|5|3|Reach${2}{R}, Sacrifice a land: Draw a card.|
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 Screaming Nemesis 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|||(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.$Tunnel of Hate${4}{R}{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.)$Whenever you attack, target attacking creature gains double strike until end of turn.|
+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.)|
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.|
Vengeful Possession|Duskmourn: House of Horror|162|U|{2}{R}|Sorcery|||Gain control of target creature until end of turn. Untap it. It gains haste until end of turn. You may discard a card. If you do, draw a card.|
-Vicious Clown|Duskmourn: House of Horror|163|C|{2}{R}|Creature - Human Clown|2|3|Whenever another creature you control with power 2 or less enters, Vicious Clown gets +2/+0 until end of turn.|
+Vicious Clown|Duskmourn: House of Horror|163|C|{2}{R}|Creature - Human Clown|2|3|Whenever another creature you control with power 2 or less enters, this creature gets +2/+0 until end of turn.|
Violent Urge|Duskmourn: House of Horror|164|U|{R}|Instant|||Target creature gets +1/+0 and gains first strike until end of turn.$Delirium -- If there are four or more card types among cards in your graveyard, that creature gains double strike until end of turn.|
Waltz of Rage|Duskmourn: House of Horror|165|R|{3}{R}{R}|Sorcery|||Target creature you control deals damage equal to its power to each other creature. Until end of turn, whenever a creature you control dies, exile the top card of your library. You may play it until the end of your next turn.|
-Altanak, the Thrice-Called|Duskmourn: House of Horror|166|U|{5}{G}{G}|Legendary Creature - Insect Beast|9|9|Trample$Whenever Altanak, the Thrice-Called becomes the target of a spell or ability an opponent controls, draw a card.${1}{G}, Discard Altanak, the Thrice-Called: Return target land card from your graveyard to the battlefield tapped.|
-Anthropede|Duskmourn: House of Horror|167|C|{3}{G}|Creature - Insect|3|4|Reach$When Anthropede enters, you may discard a card or pay {2}. When you do, destroy target Room.|
-Balustrade Wurm|Duskmourn: House of Horror|168|R|{3}{G}{G}|Creature - Wurm|5|5|This spell can't be countered.$Trample, haste$Delirium -- {2}{G}{G}: Return Balustrade Wurm 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.|
-Bashful Beastie|Duskmourn: House of Horror|169|C|{4}{G}|Creature - Beast|5|4|When Bashful Beastie dies, manifest dread.|
+Altanak, the Thrice-Called|Duskmourn: House of Horror|166|U|{5}{G}{G}|Legendary Creature - Insect Beast|9|9|Trample$Whenever Altanak becomes the target of a spell or ability an opponent controls, draw a card.${1}{G}, Discard this card: Return target land card from your graveyard to the battlefield tapped.|
+Anthropede|Duskmourn: House of Horror|167|C|{3}{G}|Creature - Insect|3|4|Reach$When this creature enters, you may discard a card or pay {2}. When you do, destroy target Room.|
+Balustrade Wurm|Duskmourn: House of Horror|168|R|{3}{G}{G}|Creature - Wurm|5|5|This spell can't be countered.$Trample, haste$Delirium -- {2}{G}{G}: 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.|
+Bashful Beastie|Duskmourn: House of Horror|169|C|{4}{G}|Creature - Beast|5|4|When this creature dies, manifest dread.|
Break Down the Door|Duskmourn: House of Horror|170|U|{2}{G}|Instant|||Choose one --$* Exile target artifact.$* Exile target enchantment.$* Manifest dread.|
Cathartic Parting|Duskmourn: House of Horror|171|U|{1}{G}|Sorcery|||The owner of target artifact or enchantment an opponent controls shuffles it into their library. You may shuffle up to four target cards from your graveyard into your library.|
-Cautious Survivor|Duskmourn: House of Horror|172|C|{3}{G}|Creature - Elf Survivor|4|4|Survival -- At the beginning of your second main phase, if Cautious Survivor is tapped, you gain 2 life.|
+Cautious Survivor|Duskmourn: House of Horror|172|C|{3}{G}|Creature - Elf Survivor|4|4|Survival -- At the beginning of your second main phase, if this creature is tapped, you gain 2 life.|
Coordinated Clobbering|Duskmourn: House of Horror|173|U|{G}|Sorcery|||Tap one or two target untapped creatures you control. They each deal damage equal to their power to target creature an opponent controls.|
-Cryptid Inspector|Duskmourn: House of Horror|174|C|{2}{G}|Creature - Elf Warrior|2|3|Vigilance$Whenever a face-down permanent you control enters and whenever Cryptid Inspector or another permanent you control is turned face up, put a +1/+1 counter on Cryptid Inspector.|
-Defiant Survivor|Duskmourn: House of Horror|175|U|{2}{G}|Creature - Human Survivor|3|2|Survival -- At the beginning of your second main phase, if Defiant Survivor is tapped, manifest dread.|
+Cryptid Inspector|Duskmourn: House of Horror|174|C|{2}{G}|Creature - Elf Warrior|2|3|Vigilance$Whenever a face-down permanent you control enters and whenever this creature or another permanent you control is turned face up, put a +1/+1 counter on this creature.|
+Defiant Survivor|Duskmourn: House of Horror|175|U|{2}{G}|Creature - Human Survivor|3|2|Survival -- At the beginning of your second main phase, if this creature is tapped, manifest dread.|
Enduring Vitality|Duskmourn: House of Horror|176|R|{1}{G}{G}|Enchantment Creature - Elk Glimmer|3|3|Vigilance$Creatures you control have "{T}: Add one mana of any color."$When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
Fear of Exposure|Duskmourn: House of Horror|177|U|{2}{G}|Enchantment Creature - Nightmare|5|4|As an additional cost to cast this spell, tap two untapped creatures and/or lands you control.$Trample|
-Flesh Burrower|Duskmourn: House of Horror|178|C|{1}{G}|Creature - Insect|2|2|Deathtouch$Whenever Flesh Burrower attacks, another target creature you control gains deathtouch until end of turn.|
+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 Grasping Longneck dies, you gain 2 life.|
-Greenhouse // Rickety Gazebo|Duskmourn: House of Horror|181|U|{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.)$Lands you control have "{T}: Add one mana of any color."$Rickety Gazebo${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, mill four cards, then return up to two permanent cards from among them to your hand.|
-Hauntwoods Shrieker|Duskmourn: House of Horror|182|M|{1}{G}{G}|Creature - Beast Mutant|3|3|Whenever Hauntwoods Shrieker 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 Hedge Shredder 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|
+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.)|
+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.|
-House Cartographer|Duskmourn: House of Horror|185|U|{1}{G}|Creature - Human Scout Survivor|2|2|Survival -- At the beginning of your second main phase, if House Cartographer is tapped, reveal cards from the top of your library until you reveal a land card. Put that card into your hand and the rest on the bottom of your library in a random order.|
-Insidious Fungus|Duskmourn: House of Horror|186|U|{G}|Creature - Fungus|1|2|{2}, Sacrifice Insidious Fungus: Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Draw a card. Then you may put a land card from your hand onto the battlefield tapped.|
-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, Rescue Beastie 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 Leyline of Mutation 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 that you cast.|
+House Cartographer|Duskmourn: House of Horror|185|U|{1}{G}|Creature - Human Scout Survivor|2|2|Survival -- At the beginning of your second main phase, if this creature is tapped, reveal cards from the top of your library until you reveal a land card. Put that card into your hand and the rest on the bottom of your library in a random order.|
+Insidious Fungus|Duskmourn: House of Horror|186|U|{G}|Creature - Fungus|1|2|{2}, Sacrifice this creature: Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Draw a card. Then you may put a land card from your hand onto the battlefield tapped.|
+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|||(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, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Weight Room${5}{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 three +1/+1 counters on that creature.|
+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.)|
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 Omnivorous Flytrap 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.|
+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.|
-Overlord of the Hauntwoods|Duskmourn: House of Horror|194|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever Overlord of the Hauntwoods enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.|
-Patchwork Beastie|Duskmourn: House of Horror|195|U|{G}|Artifact Creature - Beast|3|3|Delirium -- Patchwork Beastie can't attack or block unless there are four or more card types among cards in your graveyard.$At the beginning of your upkeep, you may mill a card.|
-Rootwise Survivor|Duskmourn: House of Horror|196|U|{3}{G}{G}|Creature - Human Survivor|3|4|Haste$Survival -- At the beginning of your second main phase, if Rootwise Survivor is tapped, put three +1/+1 counters on up to one target land you control. That land becomes a 0/0 Elemental creature in addition to its other types. It gains haste until your next turn.|
+Overlord of the Hauntwoods|Duskmourn: House of Horror|194|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever this permanent enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.|
+Patchwork Beastie|Duskmourn: House of Horror|195|U|{G}|Artifact Creature - Beast|3|3|Delirium -- This creature can't attack or block unless there are four or more card types among cards in your graveyard.$At the beginning of your upkeep, you may mill a card.|
+Rootwise Survivor|Duskmourn: House of Horror|196|U|{3}{G}{G}|Creature - Human Survivor|3|4|Haste$Survival -- At the beginning of your second main phase, if this creature is tapped, put three +1/+1 counters on up to one target land you control. That land becomes a 0/0 Elemental creature in addition to its other types. It gains haste until your next turn.|
Say Its Name|Duskmourn: House of Horror|197|C|{1}{G}|Sorcery|||Mill three cards. Then you may return a creature or land card from your graveyard to your hand.$Exile this card and two other cards named Say Its Name from your graveyard: Search your graveyard, hand, and/or library for a card named Altanak, the Thrice-Called and put it onto the battlefield. If you search your library this way, shuffle. Activate only as a sorcery.|
Slavering Branchsnapper|Duskmourn: House of Horror|198|C|{4}{G}{G}|Creature - Lizard|7|6|Trample$Forestcycling {2}|
-Spineseeker Centipede|Duskmourn: House of Horror|199|C|{2}{G}|Creature - Insect|2|1|When Spineseeker Centipede enters, search your library for a basic land card, reveal it, put it into your hand, then shuffle.$Delirium -- Spineseeker Centipede gets +1/+2 and has vigilance as long as there are four or more card types among cards in your graveyard.|
-Threats Around Every Corner|Duskmourn: House of Horror|200|U|{3}{G}|Enchantment|||When Threats Around Every Corner enters, manifest dread.$Whenever a face-down permanent you control enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.|
-Twitching Doll|Duskmourn: House of Horror|201|R|{1}{G}|Artifact Creature - Spider Toy|2|2|{T}: Add one mana of any color. Put a nest counter on Twitching Doll.${T}, Sacrifice Twitching Doll: Create a 2/2 green Spider creature token with reach for each counter on Twitching Doll. Activate only as a sorcery.|
-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, the Pummeler 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.|
+Spineseeker Centipede|Duskmourn: House of Horror|199|C|{2}{G}|Creature - Insect|2|1|When this creature enters, search your library for a basic land card, reveal it, put it into your hand, then shuffle.$Delirium -- This creature gets +1/+2 and has vigilance as long as there are four or more card types among cards in your graveyard.|
+Threats Around Every Corner|Duskmourn: House of Horror|200|U|{3}{G}|Enchantment|||When this enchantment enters, manifest dread.$Whenever a face-down permanent you control enters, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.|
+Twitching Doll|Duskmourn: House of Horror|201|R|{1}{G}|Artifact Creature - Spider Toy|2|2|{T}: Add one mana of any color. Put a nest counter on this creature.${T}, Sacrifice this creature: Create a 2/2 green Spider creature token with reach for each counter on this creature. Activate only as a sorcery.|
+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 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.)$You may play lands from your graveyard.$Forgotten Cellar${3}{G}{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, 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.|
-Wary Watchdog|Duskmourn: House of Horror|206|C|{1}{G}|Creature - Dog|3|1|When Wary Watchdog enters or dies, surveil 1.|
-Wickerfolk Thresher|Duskmourn: House of Horror|207|U|{3}{G}|Artifact Creature - Scarecrow|5|4|Delirium -- Whenever Wickerfolk Thresher 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, Abandoned Doll 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.|
-Baseball Bat|Duskmourn: House of Horror|209|U|{G}{W}|Artifact - Equipment|||When Baseball Bat enters, attach it to target creature you control.$Equipped creature gets +1/+1.$Whenever equipped creature attacks, tap up to one target creature.$Equip {3}|
+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.)|
+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.|
+Baseball Bat|Duskmourn: House of Horror|209|U|{G}{W}|Artifact - Equipment|||When this Equipment enters, attach it to target creature you control.$Equipped creature gets +1/+1.$Whenever equipped creature attacks, tap up to one target creature.$Equip {3}|
Beastie Beatdown|Duskmourn: House of Horror|210|U|{R}{G}|Sorcery|||Choose target creature you control and target creature an opponent controls.$Delirium -- If there are four or more card types among cards in your graveyard, put two +1/+1 counters on the creature you control.$The creature you control deals damage equal to its power to the creature an opponent controls.|
-Broodspinner|Duskmourn: House of Horror|211|U|{B}{G}|Creature - Spider|2|3|Reach$When Broodspinner enters, surveil 2.${4}{B}{G}, {T}, Sacrifice Broodspinner: Create a number of 1/1 black and green Insect creature tokens with flying equal to the number of card types among cards in your graveyard.|
-Disturbing Mirth|Duskmourn: House of Horror|212|U|{B}{R}|Enchantment|||When Disturbing Mirth enters, you may sacrifice another enchantment or creature. If you do, draw two cards.$When you sacrifice Disturbing Mirth, manifest dread.|
+Broodspinner|Duskmourn: House of Horror|211|U|{B}{G}|Creature - Spider|2|3|Reach$When this creature enters, surveil 2.${4}{B}{G}, {T}, Sacrifice this creature: Create a number of 1/1 black and green Insect creature tokens with flying equal to the number of card types among cards in your graveyard.|
+Disturbing Mirth|Duskmourn: House of Horror|212|U|{B}{R}|Enchantment|||When this enchantment enters, you may sacrifice another enchantment or creature. If you do, draw two cards.$When you sacrifice this enchantment, manifest dread.|
Drag to the Roots|Duskmourn: House of Horror|213|U|{2}{B}{G}|Instant|||Delirium -- This spell costs {2} less to cast as long as there are four or more card types among cards in your graveyard.$Destroy target nonland permanent.|
-Fear of Infinity|Duskmourn: House of Horror|214|U|{1}{U}{B}|Enchantment Creature - Nightmare|2|2|Flying, lifelink$Fear of Infinity can't block.$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, you may return Fear of Infinity from your graveyard to your hand.|
+Fear of Infinity|Duskmourn: House of Horror|214|U|{1}{U}{B}|Enchantment Creature - Nightmare|2|2|Flying, lifelink$This creature can't block.$Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, you may return this card from your graveyard to your hand.|
Gremlin Tamer|Duskmourn: House of Horror|215|U|{W}{U}|Creature - Human Scout|2|2|Eerie -- Whenever an enchantment you control enters and whenever you fully unlock a Room, create a 1/1 red Gremlin creature token.|
-Growing Dread|Duskmourn: House of Horror|216|U|{G}{U}|Enchantment|||Flash$When Growing Dread enters, manifest dread.$Whenever you turn a permanent face up, put a +1/+1 counter on it.|
+Growing Dread|Duskmourn: House of Horror|216|U|{G}{U}|Enchantment|||Flash$When this enchantment enters, manifest dread.$Whenever you turn a permanent face up, put a +1/+1 counter on it.|
Inquisitive Glimmer|Duskmourn: House of Horror|217|U|{W}{U}|Enchantment Creature - Fox Glimmer|2|3|Enchantment spells you cast cost {1} less to cast.$Unlock costs you pay cost {1} less.|
-Intruding Soulrager|Duskmourn: House of Horror|218|U|{U}{R}|Creature - Spirit|2|2|Vigilance${T}, Sacrifice a Room: Intruding Soulrager deals 2 damage to each opponent. Draw a card.|
+Intruding Soulrager|Duskmourn: House of Horror|218|U|{U}{R}|Creature - Spirit|2|2|Vigilance${T}, Sacrifice a Room: This creature deals 2 damage to each opponent. Draw a card.|
The Jolly Balloon Man|Duskmourn: House of Horror|219|R|{1}{R}{W}|Legendary Creature - Human Clown|1|4|Haste${1}, {T}: Create a token that's a copy of another target creature you control, except it's a 1/1 red Balloon creature in addition to its other colors and types and it has flying and haste. Sacrifice it at the beginning of the next end step. Activate only as a sorcery.|
Kaito, Bane of Nightmares|Duskmourn: House of Horror|220|M|{2}{U}{B}|Legendary Planeswalker - Kaito|4|Ninjutsu {1}{U}{B}$During your turn, as long as Kaito has one or more loyalty counters on him, he's a 3/4 Ninja creature and has hexproof.$+1: You get an emblem with "Ninjas you control get +1/+1."$0: Surveil 2. Then draw a card for each opponent who lost life this turn.$-2: Tap target creature. Put two stun counters on it.|
Marina Vendrell|Duskmourn: House of Horror|221|R|{W}{U}{B}{R}{G}|Legendary Creature - Human Warlock|3|5|When Marina Vendrell enters, reveal the top seven cards of your library. Put all enchantment cards from among them into your hand and the rest on the bottom of your library in a random order.${T}: Lock or unlock a door of target Room you control. Activate only as a sorcery.|
Midnight Mayhem|Duskmourn: House of Horror|222|U|{2}{R}{W}|Sorcery|||Create three 1/1 red Gremlin creature tokens. Gremlins you control gain menace, lifelink, and haste until end of turn.|
-Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Creature - Rat Ninja Wizard|2|2|Menace$Whenever Nashi, Searcher in the Dark deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi.|
-Niko, Light of Hope|Duskmourn: House of Horror|224|M|{2}{W}{U}|Legendary Creature - Human Wizard|3|4|When Niko, Light of Hope enters, create two Shard tokens.${2}, {T}: Exile target nonlegendary creature you control. Shards you control become copies of it until the beginning of the next end step. Return it to the battlefield under its owner's control at the beginning of the next end step.|
+Nashi, Searcher in the Dark|Duskmourn: House of Horror|223|R|{U}{B}|Legendary Creature - Rat Ninja Wizard|2|2|Menace$Whenever Nashi deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi.|
+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|||(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, destroy all creatures with power 3 or greater.$Lecture Hall${5}{U}{U}$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.)$Other permanents you control have hexproof.|
-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, Spawn Hunter 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.|
+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.)|
+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|||(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 damage equal to the number of cards in your hand to target creature an opponent controls.$Steaming Sauna${3}{U}{U}$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.)$You have no maximum hand size.$At the beginning of your end step, draw a card.|
-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 Sawblade Skinripper.$At the beginning of your end step, if you sacrificed one or more permanents this turn, Sawblade Skinripper 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 Shrewd Storyteller 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 Shroudstomper enters or attacks, each opponent loses 2 life. You gain 2 life and draw a card.|
+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.)|
+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|||(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.)$At the beginning of your first main phase, add {R}{R}. Spend this mana only to cast Room spells and unlock doors.$Misty Salon${3}{U}$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 an X/X blue Spirit creature token with flying, where X is the number of unlocked doors among Rooms you control.|
+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.)|
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 Undead Sprinter from your graveyard if a non-Zombie creature died this turn. If you do, Undead Sprinter enters with a +1/+1 counter on it.|
+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.|
-Wildfire Wickerfolk|Duskmourn: House of Horror|239|U|{R}{G}|Artifact Creature - Scarecrow|3|2|Haste$Delirium -- Wildfire Wickerfolk gets +1/+1 and has trample as long as there are four or more card types among cards in your graveyard.|
+Wildfire Wickerfolk|Duskmourn: House of Horror|239|U|{R}{G}|Artifact Creature - Scarecrow|3|2|Haste$Delirium -- This creature gets +1/+1 and has trample as long as there are four or more card types among cards in your graveyard.|
Winter, Misanthropic Guide|Duskmourn: House of Horror|240|R|{1}{B}{R}{G}|Legendary Creature - Human Warlock|3|4|Ward {2}$At the beginning of your upkeep, each player draws two cards.$Delirium -- As long as there are four or more card types among cards in your graveyard, each opponent's maximum hand size is equal to seven minus the number of those card types.|
Zimone, All-Questioning|Duskmourn: House of Horror|241|R|{1}{G}{U}|Legendary Creature - Human Wizard|1|1|At the beginning of your end step, if a land entered the battlefield under your control this turn and you control a prime number of lands, create Primo, the Indivisible, a legendary 0/0 green and blue Fractal creature token, then put that many +1/+1 counters on it.|
-Attack-in-the-Box|Duskmourn: House of Horror|242|U|{3}|Artifact Creature - Toy|2|4|Whenever Attack-in-the-Box attacks, you may have it get +4/+0 until end of turn. If you do, sacrifice it at the beginning of the next end step.|
-Bear Trap|Duskmourn: House of Horror|243|C|{1}|Artifact|||Flash${3}, {T}, Sacrifice Bear Trap: It deals 3 damage to target creature.|
-Conductive Machete|Duskmourn: House of Horror|244|U|{4}|Artifact - Equipment|||When Conductive Machete enters, manifest dread, then attach Conductive Machete to that creature.$Equipped creature gets +2/+1.$Equip {4}|
-Dissection Tools|Duskmourn: House of Horror|245|R|{5}|Artifact - Equipment|||When Dissection Tools enters, manifest dread, then attach Dissection Tools to that creature.$Equipped creature gets +2/+2 and has deathtouch and lifelink.$Equip--Sacrifice a creature.|
-Found Footage|Duskmourn: House of Horror|246|C|{1}|Artifact - Clue|||You may look at face-down creatures your opponents control any time.${2}, Sacrifice Found Footage: Surveil 2, then draw a card.|
-Friendly Teddy|Duskmourn: House of Horror|247|C|{2}|Artifact Creature - Bear Toy|2|2|When Friendly Teddy dies, each player draws a card.|
-Ghost Vacuum|Duskmourn: House of Horror|248|R|{1}|Artifact|||{T}: Exile target card from a graveyard.${6}, {T}, Sacrifice Ghost Vacuum: Put each creature card exiled with Ghost Vacuum onto the battlefield under your control with a flying counter on it. Each of them is a 1/1 Spirit in addition to its other types. Activate only as a sorcery.|
-Glimmerlight|Duskmourn: House of Horror|249|C|{2}|Artifact - Equipment|||When Glimmerlight enters, create a 1/1 white Glimmer enchantment creature token.$Equipped creature gets +1/+1.$Equip {1}|
-Haunted Screen|Duskmourn: House of Horror|250|U|{3}|Artifact|||{T}: Add {W} or {B}.${T}, Pay 1 life: Add {G}, {U}, or {R}.${7}: Put seven +1/+1 counters on Haunted Screen. It becomes a 0/0 Spirit creature in addition to its other types. Activate only once.|
-Keys to the House|Duskmourn: House of Horror|251|U|{1}|Artifact|||{1}, {T}, Sacrifice Keys to the House: Search your library for a basic land card, reveal it, put it into your hand, then shuffle.${3}, {T}, Sacrifice Keys to the House: Lock or unlock a door of target Room you control. Activate only as a sorcery.|
+Attack-in-the-Box|Duskmourn: House of Horror|242|U|{3}|Artifact Creature - Toy|2|4|Whenever this creature attacks, you may have it get +4/+0 until end of turn. If you do, sacrifice it at the beginning of the next end step.|
+Bear Trap|Duskmourn: House of Horror|243|C|{1}|Artifact|||Flash${3}, {T}, Sacrifice this artifact: It deals 3 damage to target creature.|
+Conductive Machete|Duskmourn: House of Horror|244|U|{4}|Artifact - Equipment|||When this Equipment enters, manifest dread, then attach this Equipment to that creature.$Equipped creature gets +2/+1.$Equip {4}|
+Dissection Tools|Duskmourn: House of Horror|245|R|{5}|Artifact - Equipment|||When this Equipment enters, manifest dread, then attach this Equipment to that creature.$Equipped creature gets +2/+2 and has deathtouch and lifelink.$Equip--Sacrifice a creature.|
+Found Footage|Duskmourn: House of Horror|246|C|{1}|Artifact - Clue|||You may look at face-down creatures your opponents control any time.${2}, Sacrifice this artifact: Surveil 2, then draw a card.|
+Friendly Teddy|Duskmourn: House of Horror|247|C|{2}|Artifact Creature - Bear Toy|2|2|When this creature dies, each player draws a card.|
+Ghost Vacuum|Duskmourn: House of Horror|248|R|{1}|Artifact|||{T}: Exile target card from a graveyard.${6}, {T}, Sacrifice this artifact: Put each creature card exiled with this artifact onto the battlefield under your control with a flying counter on it. Each of them is a 1/1 Spirit in addition to its other types. Activate only as a sorcery.|
+Glimmerlight|Duskmourn: House of Horror|249|C|{2}|Artifact - Equipment|||When this Equipment enters, create a 1/1 white Glimmer enchantment creature token.$Equipped creature gets +1/+1.$Equip {1}|
+Haunted Screen|Duskmourn: House of Horror|250|U|{3}|Artifact|||{T}: Add {W} or {B}.${T}, Pay 1 life: Add {G}, {U}, or {R}.${7}: Put seven +1/+1 counters on this artifact. It becomes a 0/0 Spirit creature in addition to its other types. Activate only once.|
+Keys to the House|Duskmourn: House of Horror|251|U|{1}|Artifact|||{1}, {T}, Sacrifice this artifact: Search your library for a basic land card, reveal it, put it into your hand, then shuffle.${3}, {T}, Sacrifice this artifact: Lock or unlock a door of target Room you control. Activate only as a sorcery.|
Malevolent Chandelier|Duskmourn: House of Horror|252|C|{6}|Artifact Creature - Construct|4|4|Flying${2}: Put target card from a graveyard on the bottom of its owner's library. Activate only as a sorcery.|
-Marvin, Murderous Mimic|Duskmourn: House of Horror|253|R|{2}|Legendary Artifact Creature - Toy|2|2|Marvin, Murderous Mimic has all activated abilities of creatures you control that don't have the same name as this creature.|
-Saw|Duskmourn: House of Horror|254|U|{2}|Artifact - Equipment|||Equipped creature gets +2/+0.$Whenever equipped creature attacks, you may sacrifice a permanent other than that creature or Saw. If you do, draw a card.$Equip {2}|
-Abandoned Campground|Duskmourn: House of Horror|255|C||Land|||Abandoned Campground enters tapped unless a player has 13 or less life.${T}: Add {W} or {U}.|
+Marvin, Murderous Mimic|Duskmourn: House of Horror|253|R|{2}|Legendary Artifact Creature - Toy|2|2|Marvin has all activated abilities of creatures you control that don't have the same name as this creature.|
+Saw|Duskmourn: House of Horror|254|U|{2}|Artifact - Equipment|||Equipped creature gets +2/+0.$Whenever equipped creature attacks, you may sacrifice a permanent other than that creature or this Equipment. If you do, draw a card.$Equip {2}|
+Abandoned Campground|Duskmourn: House of Horror|255|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {W} or {U}.|
Blazemire Verge|Duskmourn: House of Horror|256|R||Land|||{T}: Add {B}.${T}: Add {R}. Activate only if you control a Swamp or a Mountain.|
-Bleeding Woods|Duskmourn: House of Horror|257|C||Land|||Bleeding Woods enters tapped unless a player has 13 or less life.${T}: Add {R} or {G}.|
-Etched Cornfield|Duskmourn: House of Horror|258|C||Land|||Etched Cornfield enters tapped unless a player has 13 or less life.${T}: Add {G} or {W}.|
+Bleeding Woods|Duskmourn: House of Horror|257|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {R} or {G}.|
+Etched Cornfield|Duskmourn: House of Horror|258|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {G} or {W}.|
Floodfarm Verge|Duskmourn: House of Horror|259|R||Land|||{T}: Add {W}.${T}: Add {U}. Activate only if you control a Plains or an Island.|
Gloomlake Verge|Duskmourn: House of Horror|260|R||Land|||{T}: Add {U}.${T}: Add {B}. Activate only if you control an Island or a Swamp.|
Hushwood Verge|Duskmourn: House of Horror|261|R||Land|||{T}: Add {G}.${T}: Add {W}. Activate only if you control a Forest or a Plains.|
-Lakeside Shack|Duskmourn: House of Horror|262|C||Land|||Lakeside Shack enters tapped unless a player has 13 or less life.${T}: Add {G} or {U}.|
-Murky Sewer|Duskmourn: House of Horror|263|C||Land|||Murky Sewer enters tapped unless a player has 13 or less life.${T}: Add {U} or {B}.|
-Neglected Manor|Duskmourn: House of Horror|264|C||Land|||Neglected Manor enters tapped unless a player has 13 or less life.${T}: Add {W} or {B}.|
-Peculiar Lighthouse|Duskmourn: House of Horror|265|C||Land|||Peculiar Lighthouse enters tapped unless a player has 13 or less life.${T}: Add {U} or {R}.|
-Raucous Carnival|Duskmourn: House of Horror|266|C||Land|||Raucous Carnival enters tapped unless a player has 13 or less life.${T}: Add {R} or {W}.|
-Razortrap Gorge|Duskmourn: House of Horror|267|C||Land|||Razortrap Gorge enters tapped unless a player has 13 or less life.${T}: Add {B} or {R}.|
-Strangled Cemetery|Duskmourn: House of Horror|268|C||Land|||Strangled Cemetery enters tapped unless a player has 13 or less life.${T}: Add {B} or {G}.|
-Terramorphic Expanse|Duskmourn: House of Horror|269|C||Land|||{T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.|
+Lakeside Shack|Duskmourn: House of Horror|262|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {G} or {U}.|
+Murky Sewer|Duskmourn: House of Horror|263|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {U} or {B}.|
+Neglected Manor|Duskmourn: House of Horror|264|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {W} or {B}.|
+Peculiar Lighthouse|Duskmourn: House of Horror|265|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {U} or {R}.|
+Raucous Carnival|Duskmourn: House of Horror|266|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {R} or {W}.|
+Razortrap Gorge|Duskmourn: House of Horror|267|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {B} or {R}.|
+Strangled Cemetery|Duskmourn: House of Horror|268|C||Land|||This land enters tapped unless a player has 13 or less life.${T}: Add {B} or {G}.|
+Terramorphic Expanse|Duskmourn: House of Horror|269|C||Land|||{T}, Sacrifice this land: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.|
Thornspire Verge|Duskmourn: House of Horror|270|R||Land|||{T}: Add {R}.${T}: Add {G}. Activate only if you control a Mountain or a Forest.|
-Valgavoth's Lair|Duskmourn: House of Horror|271|R||Enchantment Land|||Hexproof$Valgavoth's Lair enters tapped. As it enters, choose a color.${T}: Add one mana of the chosen color.|
+Valgavoth's Lair|Duskmourn: House of Horror|271|R||Enchantment Land|||Hexproof$This land enters tapped. As it enters, choose a color.${T}: Add one mana of the chosen color.|
+Plains|Duskmourn: House of Horror|272|C||Basic Land - Plains|||({T}: Add {W}.)|
+Island|Duskmourn: House of Horror|273|C||Basic Land - Island|||({T}: Add {U}.)|
+Swamp|Duskmourn: House of Horror|274|C||Basic Land - Swamp|||({T}: Add {B}.)|
+Mountain|Duskmourn: House of Horror|275|C||Basic Land - Mountain|||({T}: Add {R}.)|
+Forest|Duskmourn: House of Horror|276|C||Basic Land - Forest|||({T}: Add {G}.)|
Plains|Duskmourn: House of Horror|277|C||Basic Land - Plains|||({T}: Add {W}.)|
+Plains|Duskmourn: House of Horror|278|C||Basic Land - Plains|||({T}: Add {W}.)|
Island|Duskmourn: House of Horror|279|C||Basic Land - Island|||({T}: Add {U}.)|
+Island|Duskmourn: House of Horror|280|C||Basic Land - Island|||({T}: Add {U}.)|
Swamp|Duskmourn: House of Horror|281|C||Basic Land - Swamp|||({T}: Add {B}.)|
+Swamp|Duskmourn: House of Horror|282|C||Basic Land - Swamp|||({T}: Add {B}.)|
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.)|
+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.|
+Stay Hidden, Stay Silent|Duskmourn: House of Horror|291|U|{1}{U}|Enchantment - Aura|||Enchant creature$When this Aura enters, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.${4}{U}{U}: Shuffle enchanted creature into its owner's library, then manifest dread. Activate only as a sorcery.|
+Come Back Wrong|Duskmourn: House of Horror|292|R|{2}{B}|Sorcery|||Destroy target creature. If a creature card is put into a graveyard this way, return it to the battlefield under your control. Sacrifice it at the beginning of your next end step.|
+Meathook Massacre II|Duskmourn: House of Horror|293|M|{X}{X}{B}{B}{B}{B}|Legendary Enchantment|||When Meathook Massacre II enters, each player sacrifices X creatures of their choice.$Whenever a creature you control dies, you may pay 3 life. If you do, return that card under your control with a finality counter on it.$Whenever a creature an opponent controls dies, they may pay 3 life. If they don't, return that card under your control with a finality counter on it.|
+Unstoppable Slasher|Duskmourn: House of Horror|294|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.|
+Clockwork Percussionist|Duskmourn: House of Horror|295|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|296|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.|
+Norin, Swift Survivalist|Duskmourn: House of Horror|297|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.|
+The Rollercrusher Ride|Duskmourn: House of Horror|298|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.|
+Kona, Rescue Beastie|Duskmourn: House of Horror|299|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.|
+Oblivious Bookworm|Duskmourn: House of Horror|300|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.|
+The Swarmweaver|Duskmourn: House of Horror|301|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.|
+Ghostly Dancers|Duskmourn: House of Horror|302|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.|
+Reluctant Role Model|Duskmourn: House of Horror|303|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.|
+Split Up|Duskmourn: House of Horror|304|R|{1}{W}{W}|Sorcery|||Choose one --$* Destroy all tapped creatures.$* Destroy all untapped creatures.|
+Unidentified Hovership|Duskmourn: House of Horror|305|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|
+Unwanted Remake|Duskmourn: House of Horror|306|U|{W}|Instant|||Destroy target creature. Its controller manifests dread.|
+Entity Tracker|Duskmourn: House of Horror|307|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.|
+Marina Vendrell's Grimoire|Duskmourn: House of Horror|308|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.|
+Come Back Wrong|Duskmourn: House of Horror|309|R|{2}{B}|Sorcery|||Destroy target creature. If a creature card is put into a graveyard this way, return it to the battlefield under your control. Sacrifice it at the beginning of your next end step.|
+Demonic Counsel|Duskmourn: House of Horror|310|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.|
+Meathook Massacre II|Duskmourn: House of Horror|311|M|{X}{X}{B}{B}{B}{B}|Legendary Enchantment|||When Meathook Massacre II enters, each player sacrifices X creatures of their choice.$Whenever a creature you control dies, you may pay 3 life. If you do, return that card under your control with a finality counter on it.$Whenever a creature an opponent controls dies, they may pay 3 life. If they don't, return that card under your control with a finality counter on it.|
+Unstoppable Slasher|Duskmourn: House of Horror|312|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.|
+Withering Torment|Duskmourn: House of Horror|313|U|{2}{B}|Instant|||Destroy target creature or enchantment. You lose 2 life.|
+Chainsaw|Duskmourn: House of Horror|314|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}|
+Cursed Recording|Duskmourn: House of Horror|315|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.|
+Fear of Missing Out|Duskmourn: House of Horror|316|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.|
+The Rollercrusher Ride|Duskmourn: House of Horror|317|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.|
+Waltz of Rage|Duskmourn: House of Horror|318|R|{3}{R}{R}|Sorcery|||Target creature you control deals damage equal to its power to each other creature. Until end of turn, whenever a creature you control dies, exile the top card of your library. You may play it until the end of your next turn.|
+Balustrade Wurm|Duskmourn: House of Horror|319|R|{3}{G}{G}|Creature - Wurm|5|5|This spell can't be countered.$Trample, haste$Delirium -- {2}{G}{G}: 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.|
+Hedge Shredder|Duskmourn: House of Horror|320|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|
+Insidious Fungus|Duskmourn: House of Horror|321|U|{G}|Creature - Fungus|1|2|{2}, Sacrifice this creature: Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Draw a card. Then you may put a land card from your hand onto the battlefield tapped.|
+Omnivorous Flytrap|Duskmourn: House of Horror|322|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.|
+Under the Skin|Duskmourn: House of Horror|323|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|324|R|{X}{X}{G}|Sorcery|||Manifest dread X times, then put X +1/+1 counters on each of those creatures.|
+Peer Past the Veil|Duskmourn: House of Horror|325|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.|
+Ghost Vacuum|Duskmourn: House of Horror|326|R|{1}|Artifact|||{T}: Exile target card from a graveyard.${6}, {T}, Sacrifice this artifact: Put each creature card exiled with this artifact onto the battlefield under your control with a flying counter on it. Each of them is a 1/1 Spirit in addition to its other types. Activate only as a sorcery.|
+Valgavoth's Lair|Duskmourn: House of Horror|327|R||Enchantment Land|||Hexproof$This land enters tapped. As it enters, choose a color.${T}: Add one mana of the chosen color.|
+Kaito, Bane of Nightmares|Duskmourn: House of Horror|328|M|{2}{U}{B}|Legendary Planeswalker - Kaito|4|Ninjutsu {1}{U}{B}$During your turn, as long as Kaito has one or more loyalty counters on him, he's a 3/4 Ninja creature and has hexproof.$+1: You get an emblem with "Ninjas you control get +1/+1."$0: Surveil 2. Then draw a card for each opponent who lost life this turn.$-2: Tap target creature. Put two stun counters on it.|
+Blazemire Verge|Duskmourn: House of Horror|329|R||Land|||{T}: Add {B}.${T}: Add {R}. Activate only if you control a Swamp or a Mountain.|
+Floodfarm Verge|Duskmourn: House of Horror|330|R||Land|||{T}: Add {W}.${T}: Add {U}. Activate only if you control a Plains or an Island.|
+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.)|
+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.|
+Razorkin Needlehead|Duskmourn: House of Horror|347|R|{R}{R}|Creature - Human Assassin|2|2|This creature has first strike during your turn.$Whenever an opponent draws a card, this creature deals 1 damage to them.|
+Screaming Nemesis|Duskmourn: House of Horror|348|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.|
+Hauntwoods Shrieker|Duskmourn: House of Horror|349|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.|
+Undead Sprinter|Duskmourn: House of Horror|350|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.|
+The Wandering Rescuer|Duskmourn: House of Horror|351|M|{3}{W}{W}|Legendary Creature - Human Samurai Noble|3|4|Flash$Convoke$Double strike$Other tapped creatures you control have hexproof.|
+Valgavoth, Terror Eater|Duskmourn: House of Horror|352|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.|
+Tyvar, the Pummeler|Duskmourn: House of Horror|353|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.|
+Kaito, Bane of Nightmares|Duskmourn: House of Horror|354|M|{2}{U}{B}|Legendary Planeswalker - Kaito|4|Ninjutsu {1}{U}{B}$During your turn, as long as Kaito has one or more loyalty counters on him, he's a 3/4 Ninja creature and has hexproof.$+1: You get an emblem with "Ninjas you control get +1/+1."$0: Surveil 2. Then draw a card for each opponent who lost life this turn.$-2: Tap target creature. Put two stun counters on it.|
+Niko, Light of Hope|Duskmourn: House of Horror|355|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.|
+Toby, Beastie Befriender|Duskmourn: House of Horror|356|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.|
+The Mindskinner|Duskmourn: House of Horror|357|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.|
+Kona, Rescue Beastie|Duskmourn: House of Horror|358|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.|
+The Jolly Balloon Man|Duskmourn: House of Horror|359|R|{1}{R}{W}|Legendary Creature - Human Clown|1|4|Haste${1}, {T}: Create a token that's a copy of another target creature you control, except it's a 1/1 red Balloon creature in addition to its other colors and types and it has flying and haste. Sacrifice it at the beginning of the next end step. Activate only as a sorcery.|
+Marina Vendrell|Duskmourn: House of Horror|360|R|{W}{U}{B}{R}{G}|Legendary Creature - Human Warlock|3|5|When Marina Vendrell enters, reveal the top seven cards of your library. Put all enchantment cards from among them into your hand and the rest on the bottom of your library in a random order.${T}: Lock or unlock a door of target Room you control. Activate only as a sorcery.|
+Nashi, Searcher in the Dark|Duskmourn: House of Horror|361|R|{U}{B}|Legendary Creature - Rat Ninja Wizard|2|2|Menace$Whenever Nashi deals combat damage to a player, you mill that many cards. You may put any number of legendary and/or enchantment cards from among them into your hand. If you put no cards into your hand this way, put a +1/+1 counter on Nashi.|
+Rip, Spawn Hunter|Duskmourn: House of Horror|362|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.|
+The Swarmweaver|Duskmourn: House of Horror|363|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.|
+Victor, Valgavoth's Seneschal|Duskmourn: House of Horror|364|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.|
+Winter, Misanthropic Guide|Duskmourn: House of Horror|365|R|{1}{B}{R}{G}|Legendary Creature - Human Warlock|3|4|Ward {2}$At the beginning of your upkeep, each player draws two cards.$Delirium -- As long as there are four or more card types among cards in your graveyard, each opponent's maximum hand size is equal to seven minus the number of those card types.|
+Zimone, All-Questioning|Duskmourn: House of Horror|366|R|{1}{G}{U}|Legendary Creature - Human Wizard|1|1|At the beginning of your end step, if a land entered the battlefield under your control this turn and you control a prime number of lands, create Primo, the Indivisible, a legendary 0/0 green and blue Fractal creature token, then put that many +1/+1 counters on it.|
+Marvin, Murderous Mimic|Duskmourn: House of Horror|367|R|{2}|Legendary Artifact Creature - Toy|2|2|Marvin has all activated abilities of creatures you control that don't have the same name as this creature.|
+Enduring Innocence|Duskmourn: House of Horror|368|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.|
+Leyline of Hope|Duskmourn: House of Horror|369|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.|
+Overlord of the Mistmoors|Duskmourn: House of Horror|370|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever this permanent enters or attacks, create two 2/1 white Insect creature tokens with flying.|
+Enduring Curiosity|Duskmourn: House of Horror|371|R|{2}{U}{U}|Enchantment Creature - Cat Glimmer|4|3|Flash$Whenever a creature you control deals combat damage to a player, draw a card.$When Enduring Curiosity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Leyline of Transformation|Duskmourn: House of Horror|372|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.|
+Overlord of the Floodpits|Duskmourn: House of Horror|373|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.|
+Enduring Tenacity|Duskmourn: House of Horror|374|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.|
+Grievous Wound|Duskmourn: House of Horror|375|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.|
+Leyline of the Void|Duskmourn: House of Horror|376|R|{2}{B}{B}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$If a card would be put into an opponent's graveyard from anywhere, exile it instead.|
+Overlord of the Balemurk|Duskmourn: House of Horror|377|M|{3}{B}{B}|Enchantment Creature - Avatar Horror|5|5|Impending 5--{1}{B}$Whenever this permanent enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.|
+Enduring Courage|Duskmourn: House of Horror|378|R|{2}{R}{R}|Enchantment Creature - Dog Glimmer|3|3|Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn.$When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Leyline of Resonance|Duskmourn: House of Horror|379|R|{2}{R}{R}|Enchantment|||If this card is in your opening hand, you may begin the game with it on the battlefield.$Whenever you cast an instant or sorcery spell that targets only a single creature you control, copy that spell. You may choose new targets for the copy.|
+Overlord of the Boilerbilges|Duskmourn: House of Horror|380|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.|
+Enduring Vitality|Duskmourn: House of Horror|381|R|{1}{G}{G}|Enchantment Creature - Elk Glimmer|3|3|Vigilance$Creatures you control have "{T}: Add one mana of any color."$When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Leyline of Mutation|Duskmourn: House of Horror|382|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.|
+Overlord of the Hauntwoods|Duskmourn: House of Horror|383|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever this permanent enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.|
+Twitching Doll|Duskmourn: House of Horror|384|R|{1}{G}|Artifact Creature - Spider Toy|2|2|{T}: Add one mana of any color. Put a nest counter on this creature.${T}, Sacrifice this creature: Create a 2/2 green Spider creature token with reach for each counter on this creature. Activate only as a sorcery.|
+Dissection Tools|Duskmourn: House of Horror|385|R|{5}|Artifact - Equipment|||When this Equipment enters, manifest dread, then attach this Equipment to that creature.$Equipped creature gets +2/+2 and has deathtouch and lifelink.$Equip--Sacrifice a creature.|
+Enduring Innocence|Duskmourn: House of Horror|386|M|{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.|
+Overlord of the Mistmoors|Duskmourn: House of Horror|387|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever this permanent enters or attacks, create two 2/1 white Insect creature tokens with flying.|
+Enduring Curiosity|Duskmourn: House of Horror|388|M|{2}{U}{U}|Enchantment Creature - Cat Glimmer|4|3|Flash$Whenever a creature you control deals combat damage to a player, draw a card.$When Enduring Curiosity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Floodpits|Duskmourn: House of Horror|389|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.|
+Enduring Tenacity|Duskmourn: House of Horror|390|M|{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.|
+Overlord of the Balemurk|Duskmourn: House of Horror|391|M|{3}{B}{B}|Enchantment Creature - Avatar Horror|5|5|Impending 5--{1}{B}$Whenever this permanent enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.|
+Enduring Courage|Duskmourn: House of Horror|392|M|{2}{R}{R}|Enchantment Creature - Dog Glimmer|3|3|Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn.$When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Boilerbilges|Duskmourn: House of Horror|393|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.|
+Enduring Vitality|Duskmourn: House of Horror|394|M|{1}{G}{G}|Enchantment Creature - Elk Glimmer|3|3|Vigilance$Creatures you control have "{T}: Add one mana of any color."$When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Hauntwoods|Duskmourn: House of Horror|395|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever this permanent enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.|
+Enduring Innocence|Duskmourn: House of Horror|396|M|{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.|
+Overlord of the Mistmoors|Duskmourn: House of Horror|397|M|{5}{W}{W}|Enchantment Creature - Avatar Horror|6|6|Impending 4--{2}{W}{W}$Whenever this permanent enters or attacks, create two 2/1 white Insect creature tokens with flying.|
+Enduring Curiosity|Duskmourn: House of Horror|398|M|{2}{U}{U}|Enchantment Creature - Cat Glimmer|4|3|Flash$Whenever a creature you control deals combat damage to a player, draw a card.$When Enduring Curiosity dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Floodpits|Duskmourn: House of Horror|399|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.|
+Enduring Tenacity|Duskmourn: House of Horror|400|M|{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.|
+Overlord of the Balemurk|Duskmourn: House of Horror|401|M|{3}{B}{B}|Enchantment Creature - Avatar Horror|5|5|Impending 5--{1}{B}$Whenever this permanent enters or attacks, mill four cards, then you may return a non-Avatar creature card or a planeswalker card from your graveyard to your hand.|
+Enduring Courage|Duskmourn: House of Horror|402|M|{2}{R}{R}|Enchantment Creature - Dog Glimmer|3|3|Whenever another creature you control enters, it gets +2/+0 and gains haste until end of turn.$When Enduring Courage dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Boilerbilges|Duskmourn: House of Horror|403|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.|
+Enduring Vitality|Duskmourn: House of Horror|404|M|{1}{G}{G}|Enchantment Creature - Elk Glimmer|3|3|Vigilance$Creatures you control have "{T}: Add one mana of any color."$When Enduring Vitality dies, if it was a creature, return it to the battlefield under its owner's control. It's an enchantment.|
+Overlord of the Hauntwoods|Duskmourn: House of Horror|405|M|{3}{G}{G}|Enchantment Creature - Avatar Horror|6|5|Impending 4--{1}{G}{G}$Whenever this permanent enters or attacks, create a tapped colorless land token named Everywhere that is every basic land type.|
+The Wandering Rescuer|Duskmourn: House of Horror|406|M|{3}{W}{W}|Legendary Creature - Human Samurai Noble|3|4|Flash$Convoke$Double strike$Other tapped creatures you control have hexproof.|
+Valgavoth, Terror Eater|Duskmourn: House of Horror|407|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.|
+Tyvar, the Pummeler|Duskmourn: House of Horror|408|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.|
+Kaito, Bane of Nightmares|Duskmourn: House of Horror|409|M|{2}{U}{B}|Legendary Planeswalker - Kaito|4|Ninjutsu {1}{U}{B}$During your turn, as long as Kaito has one or more loyalty counters on him, he's a 3/4 Ninja creature and has hexproof.$+1: You get an emblem with "Ninjas you control get +1/+1."$0: Surveil 2. Then draw a card for each opponent who lost life this turn.$-2: Tap target creature. Put two stun counters on it.|
+Niko, Light of Hope|Duskmourn: House of Horror|410|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.|
+Shardmage's Rescue|Duskmourn: House of Horror|411|U|{W}|Enchantment - Aura|||Flash$Enchant creature you control$As long as this Aura entered this turn, enchanted creature has hexproof.$Enchanted creature gets +1/+1.|
+Valgavoth's Faithful|Duskmourn: House of Horror|412|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.|
+Pyroclasm|Duskmourn: House of Horror|413|U|{1}{R}|Sorcery|||Pyroclasm deals 2 damage to each creature.|
+Drag to the Roots|Duskmourn: House of Horror|414|U|{2}{B}{G}|Instant|||Delirium -- This spell costs {2} less to cast as long as there are four or more card types among cards in your graveyard.$Destroy target nonland permanent.|
+Inquisitive Glimmer|Duskmourn: House of Horror|415|U|{W}{U}|Enchantment Creature - Fox Glimmer|2|3|Enchantment spells you cast cost {1} less to cast.$Unlock costs you pay cost {1} less.|
+Grievous Wound|Duskmourn: House of Horror|416|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.|
+Twitching Doll|Duskmourn: House of Horror|417|R|{1}{G}|Artifact Creature - Spider Toy|2|2|{T}: Add one mana of any color. Put a nest counter on this creature.${T}, Sacrifice this creature: Create a 2/2 green Spider creature token with reach for each counter on this creature. Activate only as a sorcery.|
Sire of Seven Deaths|Foundations|1|M|{7}|Creature - Eldrazi|7|7|First strike, vigilance$Menace, trample$Reach, lifelink$Ward--Pay 7 life.|
Arahbo, the First Fang|Foundations|2|R|{2}{W}|Legendary Creature - Cat Avatar|2|2|Other Cats you control get +1/+1.$Whenever Arahbo or another nontoken Cat you control enters, create a 1/1 white Cat creature token.|
Armasaur Guide|Foundations|3|C|{4}{W}|Creature - Dinosaur|4|4|Vigilance$Whenever you attack with three or more creatures, put a +1/+1 counter on target creature you control.|