mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Merge branch 'master' into refactor/clean-filter-logic
This commit is contained in:
commit
836caec201
499 changed files with 8221 additions and 3606 deletions
|
|
@ -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;
|
|||
* <p>
|
||||
* 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<String, List<Integer>> 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<String> foundGameChangers = new ArrayList<>();
|
||||
private final List<String> foundInfiniteCombos = new ArrayList<>();
|
||||
|
|
@ -41,28 +96,14 @@ public class BracketLegalityLabel extends LegalityLabel {
|
|||
|
||||
private final List<String> badCards = new ArrayList<>();
|
||||
private final List<String> fullGameChanges = new ArrayList<>();
|
||||
private final Set<String> 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<String> showInfo = new ArrayList<>();
|
||||
if (this.badCards.isEmpty()) {
|
||||
showInfo.add("<p>Deck is <span style='color:green;font-weight:bold;'>GOOD</span> for " + this.level + "</p>");
|
||||
showInfo.add(String.format("<span style='font-weight:bold;font-size:%dpx;'><p>Deck is <span style='color:green;'>GOOD</span> for %s</p></span>",
|
||||
infoFontHeaderSize,
|
||||
this.fullName
|
||||
));
|
||||
} else {
|
||||
showInfo.add("<p>Deck is <span style='color:#BF544A;font-weight:bold;'>BAD</span> for " + this.level + "</p>");
|
||||
showInfo.add(String.format("<span style='font-weight:bold;font-size:%dpx;'><p>Deck is <span style='color:#BF544A;'>BAD</span> for %s</p></span>",
|
||||
infoFontHeaderSize,
|
||||
this.fullName
|
||||
));
|
||||
showInfo.add("<p>(click here to select all bad cards)</p>");
|
||||
}
|
||||
|
||||
Map<String, List<String>> 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("<br>");
|
||||
showInfo.add("<br>");
|
||||
showInfo.add("<span style='font-weight:bold;'>" + group + ": " + cards.size() + "</span>");
|
||||
if (!cards.isEmpty()) {
|
||||
showInfo.add("<ul style=\"font-size: " + infoFontSize + "px; width: " + TOOLTIP_TABLE_WIDTH + "px; padding-left: 10px; margin: 0;\">");
|
||||
showInfo.add("<span style='font-weight:bold;font-size: " + infoFontTextSize + "px;'>" + group + "</span>");
|
||||
if (cards.isEmpty()) {
|
||||
showInfo.add("<ul style=\"font-size: " + infoFontTextSize + "px; width: " + TOOLTIP_TABLE_WIDTH + "px; padding-left: 10px; margin: 0;\">");
|
||||
showInfo.add("<li style=\"margin-bottom: 2px;\">no cards</li>");
|
||||
showInfo.add("</ul>");
|
||||
} else {
|
||||
showInfo.add("<ul style=\"font-size: " + infoFontTextSize + "px; width: " + TOOLTIP_TABLE_WIDTH + "px; padding-left: 10px; margin: 0;\">");
|
||||
cards.forEach(s -> showInfo.add(String.format("<li style=\"margin-bottom: 2px;\">%s</li>", s)));
|
||||
showInfo.add("</ul>");
|
||||
}
|
||||
|
|
@ -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 = " (<span style='color:#BF544A;'>%s of %s</span>)";
|
||||
} else {
|
||||
info = " (<span>%s of %s</span>)";
|
||||
}
|
||||
|
||||
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<String> 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<Card> deckCards = new ArrayList<>();
|
||||
Set<Card> foundCards = new HashSet<>();
|
||||
deckCards.addAll(deck.getCards());
|
||||
deckCards.addAll(deck.getSideboard());
|
||||
for (Card card1 : deckCards) {
|
||||
for (Card card2 : deckCards) {
|
||||
if (card1 == card2) {
|
||||
continue;
|
||||
}
|
||||
List<String> 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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String, String> 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();
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import java.util.List;
|
|||
/**
|
||||
* Part of testable game dialogs
|
||||
* <p>
|
||||
* It's a complex dialog with 2 steps: choose targets list + distribute amount between targets
|
||||
* <p>
|
||||
* Supported methods:
|
||||
* - player.chooseTarget(amount)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import java.util.List;
|
|||
/**
|
||||
* Part of testable game dialogs
|
||||
* <p>
|
||||
* Its simple dialog to get some amount (example: part of chooseTargetAmount)
|
||||
* <p>
|
||||
* Supported methods:
|
||||
* - player.getAmount()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* <p>
|
||||
* Its simple dialog to get distributed value between multiple options (example: part of combat damage distributing)
|
||||
* <p>
|
||||
* 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<MultiAmountMessage> amountOptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param options min, max, default
|
||||
*/
|
||||
public GetMultiAmountTestableDialog(boolean isYou, String info, int totalMin, int totalMax, List<List<Integer>> 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<Integer> single : options) {
|
||||
optionNumber++;
|
||||
String mes = "<font color=green>option</font> " + optionNumber + " with html";
|
||||
this.amountOptions.add(new MultiAmountMessage(mes, single.get(0), single.get(1), single.get(2)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||
Player choosingPlayer = this.isYou ? player : opponent;
|
||||
//String message = "<font color=green>message</font> with html";
|
||||
List<Integer> chooseRes;
|
||||
List<MultiAmountMessage> options = this.amountOptions.stream().map(MultiAmountMessage::copy).collect(Collectors.toList());
|
||||
chooseRes = choosingPlayer.getMultiAmountWithIndividualConstraints(
|
||||
Outcome.Benefit,
|
||||
options,
|
||||
this.totalMin,
|
||||
this.totalMax,
|
||||
MultiAmountType.DAMAGE,
|
||||
game
|
||||
);
|
||||
|
||||
List<String> 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<Boolean> 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<List<Integer>> genSameOptions(int amount, int min, int max, int def) {
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
// min, max, default
|
||||
res.add(Arrays.asList(min, max, def));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ import java.util.stream.Collectors;
|
|||
* [x] choosePile
|
||||
* [x] announceX
|
||||
* [x] getAmount
|
||||
* [ ] getMultiAmountWithIndividualConstraints // TODO: implement
|
||||
* [x] getMultiAmountWithIndividualConstraints
|
||||
* <p>
|
||||
* 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) {
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@
|
|||
<tournamentType name="Booster Draft Swiss (Cube)" jar="mage-tournament-boosterdraft-${project.version}.jar" className="mage.tournament.BoosterDraftSwissTournament" typeName="mage.tournament.BoosterDraftSwissCubeTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Random)" jar="mage-tournament-boosterdraft-${project.version}.jar" className="mage.tournament.RandomBoosterDraftSwissTournament" typeName="mage.tournament.RandomBoosterDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Reshuffled)" jar="mage-tournament-boosterdraft-${project.version}.jar" className="mage.tournament.ReshuffledBoosterDraftSwissTournament" typeName="mage.tournament.ReshuffledBoosterDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Rich Man)" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.RichManDraftSwissTournament" typeName="mage.tournament.RichManDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Rich Man Cube)" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.RichManCubeDraftSwissTournament" typeName="mage.tournament.RichManCubeDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Rich Man)" jar="mage-tournament-boosterdraft-${project.version}.jar" className="mage.tournament.RichManDraftSwissTournament" typeName="mage.tournament.RichManDraftSwissTournamentType"/>
|
||||
<tournamentType name="Booster Draft Swiss (Rich Man Cube)" jar="mage-tournament-boosterdraft-${project.version}.jar" className="mage.tournament.RichManCubeDraftSwissTournament" typeName="mage.tournament.RichManCubeDraftSwissTournamentType"/>
|
||||
<tournamentType name="Sealed Elimination" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationTournamentType"/>
|
||||
<tournamentType name="Sealed Elimination (Cube)" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedEliminationTournament" typeName="mage.tournament.SealedEliminationCubeTournamentType"/>
|
||||
<tournamentType name="Sealed Swiss" jar="mage-tournament-sealed-${project.version}.jar" className="mage.tournament.SealedSwissTournament" typeName="mage.tournament.SealedSwissTournamentType"/>
|
||||
|
|
@ -108,62 +108,62 @@
|
|||
</tournamentTypes>
|
||||
<draftCubes>
|
||||
<!-- main cubes -->
|
||||
<draftCube name="Cube From Deck" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.CubeFromDeck"/>
|
||||
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCube"/>
|
||||
<draftCube name="MTGO Vintage Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCube"/>
|
||||
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegendaryCube"/>
|
||||
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegendaryCubeApril2016"/>
|
||||
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.ModernCube2017"/>
|
||||
<draftCube name="MTGO Khans Expanded Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.KhansExpandedCube"/>
|
||||
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.MTGOMarchCube2014"/>
|
||||
<draftCube name="MTGA Cube 2020 April" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.MTGACube2020April"/>
|
||||
<draftCube name="Cube From Deck" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.CubeFromDeck"/>
|
||||
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube"/>
|
||||
<draftCube name="MTGO Vintage Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube"/>
|
||||
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCube"/>
|
||||
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
|
||||
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ModernCube2017"/>
|
||||
<draftCube name="MTGO Khans Expanded Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.KhansExpandedCube"/>
|
||||
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
|
||||
<draftCube name="MTGA Cube 2020 April" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGACube2020April"/>
|
||||
<!-- named cubes (will be removed someday) -->
|
||||
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.ScgConCube2018December"/>
|
||||
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.PeasantsToolboxCube"/>
|
||||
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.MTGCube"/>
|
||||
<draftCube name="The Pauper Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.PauperCube"/>
|
||||
<draftCube name="Ben's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.BensCube"/>
|
||||
<draftCube name="Cube Tutor 360 Pauper" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.CubeTutor360Pauper"/>
|
||||
<draftCube name="Cube Tutor 720" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.CubeTutor720"/>
|
||||
<draftCube name="Eric Klug's Pro Tour Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.EricKlugsProTourCube"/>
|
||||
<draftCube name="Guillaume Matignon's Jenny's/Johnny's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.GuillaumeMatignonsJennysJohnnysCube"/>
|
||||
<draftCube name="Jim Davis's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.JimDavisCube"/>
|
||||
<draftCube name="Joseph Vasoli's Peasant Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.JosephVasolisPeasantCube"/>
|
||||
<draftCube name="Sam Black's No Search Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.SamBlacksCube"/>
|
||||
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
|
||||
<draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.MonoBlueCube"/>
|
||||
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
|
||||
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
|
||||
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>
|
||||
<draftCube name="The Pauper Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PauperCube"/>
|
||||
<draftCube name="Ben's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.BensCube"/>
|
||||
<draftCube name="Cube Tutor 360 Pauper" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.CubeTutor360Pauper"/>
|
||||
<draftCube name="Cube Tutor 720" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.CubeTutor720"/>
|
||||
<draftCube name="Eric Klug's Pro Tour Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.EricKlugsProTourCube"/>
|
||||
<draftCube name="Guillaume Matignon's Jenny's/Johnny's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.GuillaumeMatignonsJennysJohnnysCube"/>
|
||||
<draftCube name="Jim Davis's Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JimDavisCube"/>
|
||||
<draftCube name="Joseph Vasoli's Peasant Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.JosephVasolisPeasantCube"/>
|
||||
<draftCube name="Sam Black's No Search Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.SamBlacksCube"/>
|
||||
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
|
||||
<draftCube name="Mono Blue Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MonoBlueCube"/>
|
||||
<!-- outdated cubes - will be removed on next releases -->
|
||||
<!--
|
||||
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeMarch2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2015 September" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeSeptember2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 January" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeJanuary2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 September" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeSeptember2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 January" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeJanuary2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 April" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeApril2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2018 February" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCube2018February"/>
|
||||
<draftCube name="MTGO Legacy Cube 2019 July" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeJuly2019"/>
|
||||
<draftCube name="MTGO Legacy Cube 2021 May" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.LegacyCubeMay2021"/>
|
||||
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2015 September" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2015"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 January" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2016 September" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeSeptember2016"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 January" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJanuary2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2017 April" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeApril2017"/>
|
||||
<draftCube name="MTGO Legacy Cube 2018 February" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube2018February"/>
|
||||
<draftCube name="MTGO Legacy Cube 2019 July" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeJuly2019"/>
|
||||
<draftCube name="MTGO Legacy Cube 2021 May" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMay2021"/>
|
||||
-->
|
||||
<!-- outdated cubes - will be removed on next releases -->
|
||||
<!--
|
||||
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCube2013"/>
|
||||
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCube2014"/>
|
||||
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCube2015"/>
|
||||
<draftCube name="MTGO Vintage Cube 2016" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCube2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2016" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJune2016"/>
|
||||
<draftCube name="MTGO Vintage Cube November 2016" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeNovember2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2017" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJune2017"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2017" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeDecember2017"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJune2018"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeDecember2018"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJune2019"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeDecember2019"/>
|
||||
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeApril2020"/>
|
||||
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJuly2020"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2020" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeDecember2020"/>
|
||||
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeJuly2021"/>
|
||||
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeFebruary2022"/>
|
||||
<draftCube name="MTGO Vintage Cube October 2023" jar="mage-tournament-booster-draft-${project.version}.jar" classNam="mage.tournament.cubes.VintageCubeOctober2023"/>
|
||||
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/>
|
||||
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2014"/>
|
||||
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2015"/>
|
||||
<draftCube name="MTGO Vintage Cube 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2016"/>
|
||||
<draftCube name="MTGO Vintage Cube November 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeNovember2016"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2017"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2017"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
|
||||
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
|
||||
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeApril2020"/>
|
||||
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJuly2020"/>
|
||||
<draftCube name="MTGO Vintage Cube December 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2020"/>
|
||||
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJuly2021"/>
|
||||
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeFebruary2022"/>
|
||||
<draftCube name="MTGO Vintage Cube October 2023" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeOctober2023"/>
|
||||
-->
|
||||
</draftCubes>
|
||||
<deckTypes>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}, "");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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} <i>(energy counters)</i> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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.\"");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
// <i>Hate</i> — 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,
|
||||
"<i>Hate</i> — 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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
+ " <i>(It can't be blocked except by two or more creatures.)</i>"
|
||||
);
|
||||
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());
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<Permanen
|
|||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<Permanent> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
//<i>Metalcraft</i> — 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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
//<i>Metalcraft</i> — 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) {
|
||||
|
|
|
|||
|
|
@ -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")));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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}")));
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. " +
|
||||
"<i>(A creature with menace can't be blocked except by two or more creatures.)</i>"
|
||||
));
|
||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
|
||||
new MenaceAbility(false), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES
|
||||
)).withInterveningIf(KickedCondition.ONCE));
|
||||
}
|
||||
|
||||
private BogBadger(final BogBadger card) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
142
Mage.Sets/src/mage/cards/b/BorosStrikeCaptain.java
Normal file
142
Mage.Sets/src/mage/cards/b/BorosStrikeCaptain.java
Normal file
|
|
@ -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<UUID, Set<MageObjectReference>> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Permanent> {
|
|||
|
||||
@Override
|
||||
public boolean apply(ObjectSourcePlayer<Permanent> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue