Merge remote-tracking branch 'magefree/master'

This commit is contained in:
Samuel Sandeen 2016-09-02 19:44:51 -04:00
commit 85dc15c5dc
61 changed files with 1443 additions and 702 deletions

1
.gitignore vendored
View file

@ -92,6 +92,7 @@ hs_err*.log
*.txt *.txt
Mage.Client/serverlist.txt Mage.Client/serverlist.txt
/bin/ /bin/
/out/
/target/ /target/
client_secrets.json client_secrets.json

View file

@ -12,6 +12,7 @@ public class CardDownloadData {
private String downloadName; private String downloadName;
private String set; private String set;
private String tokenSetCode; private String tokenSetCode;
private String tokenDescriptor;
private String collectorId; private String collectorId;
private Integer type; private Integer type;
private boolean token; private boolean token;
@ -23,15 +24,15 @@ public class CardDownloadData {
private boolean usesVariousArt; private boolean usesVariousArt;
private boolean isType2; private boolean isType2;
public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode) { public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor) {
this(name, set, collectorId, usesVariousArt, type, tokenSetCode, false); this(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor, false);
} }
public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, boolean token) { public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor, boolean token) {
this(name, set, collectorId, usesVariousArt, type, tokenSetCode, token, false, false); this(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor, token, false, false);
} }
public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, boolean token, boolean twoFacedCard, boolean secondSide) { public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor, boolean token, boolean twoFacedCard, boolean secondSide) {
this.name = name; this.name = name;
this.set = set; this.set = set;
this.collectorId = collectorId; this.collectorId = collectorId;
@ -41,6 +42,7 @@ public class CardDownloadData {
this.twoFacedCard = twoFacedCard; this.twoFacedCard = twoFacedCard;
this.secondSide = secondSide; this.secondSide = secondSide;
this.tokenSetCode = tokenSetCode; this.tokenSetCode = tokenSetCode;
this.tokenDescriptor = tokenDescriptor;
} }
public CardDownloadData(final CardDownloadData card) { public CardDownloadData(final CardDownloadData card) {
@ -117,7 +119,7 @@ public class CardDownloadData {
public String getSet() { public String getSet() {
return set; return set;
} }
public void setSet(String set) { public void setSet(String set) {
this.set = set; this.set = set;
} }
@ -130,6 +132,13 @@ public class CardDownloadData {
this.tokenSetCode = tokenSetCode; this.tokenSetCode = tokenSetCode;
} }
public String getTokenDescriptor() {
return tokenDescriptor;
}
public void setTokenDescriptor(String tokenDescriptor) {
this.tokenDescriptor = tokenDescriptor;
}
public boolean isToken() { public boolean isToken() {
return token; return token;
} }

View file

@ -239,7 +239,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
TFile file; TFile file;
for (CardInfo card : allCards) { for (CardInfo card : allCards) {
if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty()) { if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty()) {
CardDownloadData url = new CardDownloadData(card.getName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", false, card.isDoubleFaced(), card.isNightCard()); CardDownloadData url = new CardDownloadData(card.getName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(),
0, "", "", false, card.isDoubleFaced(), card.isNightCard());
file = new TFile(CardImageUtils.generateImagePath(url)); file = new TFile(CardImageUtils.generateImagePath(url));
if (!file.exists()) { if (!file.exists()) {
return true; return true;
@ -285,7 +286,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
&& !ignoreUrls.contains(card.getSetCode())) { && !ignoreUrls.contains(card.getSetCode())) {
String cardName = card.getName(); String cardName = card.getName();
boolean isType2 = type2SetsFilter.contains(card.getSetCode()); boolean isType2 = type2SetsFilter.contains(card.getSetCode());
CardDownloadData url = new CardDownloadData(cardName, card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", false, card.isDoubleFaced(), card.isNightCard()); CardDownloadData url = new CardDownloadData(cardName, card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), card.isNightCard());
if (url.getUsesVariousArt()) { if (url.getUsesVariousArt()) {
url.setDownloadName(createDownloadName(card)); url.setDownloadName(createDownloadName(card));
} }
@ -299,7 +300,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
if (card.getSecondSideName() == null || card.getSecondSideName().trim().isEmpty()) { if (card.getSecondSideName() == null || card.getSecondSideName().trim().isEmpty()) {
throw new IllegalStateException("Second side card can't have empty name."); throw new IllegalStateException("Second side card can't have empty name.");
} }
url = new CardDownloadData(card.getSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", false, card.isDoubleFaced(), true); url = new CardDownloadData(card.getSecondSideName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), true);
url.setType2(isType2); url.setType2(isType2);
allCardsUrls.add(url); allCardsUrls.add(url);
} }
@ -307,7 +308,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
if (card.getFlipCardName() == null || card.getFlipCardName().trim().isEmpty()) { if (card.getFlipCardName() == null || card.getFlipCardName().trim().isEmpty()) {
throw new IllegalStateException("Flipped card can't have empty name."); throw new IllegalStateException("Flipped card can't have empty name.");
} }
url = new CardDownloadData(card.getFlipCardName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", false, card.isDoubleFaced(), card.isNightCard()); url = new CardDownloadData(card.getFlipCardName(), card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), card.isNightCard());
url.setFlipCard(true); url.setFlipCard(true);
url.setFlippedSide(true); url.setFlippedSide(true);
url.setType2(isType2); url.setType2(isType2);
@ -385,19 +386,19 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
} }
if (params[1].toLowerCase().equals("generate") && params[2].startsWith("TOK:")) { if (params[1].toLowerCase().equals("generate") && params[2].startsWith("TOK:")) {
String set = params[2].substring(4); String set = params[2].substring(4);
CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", true); CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true);
list.add(card); list.add(card);
} else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM:")) { } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM:")) {
String set = params[2].substring(7); String set = params[2].substring(7);
CardDownloadData card = new CardDownloadData("Emblem " + params[3], set, "0", false, type, "", true); CardDownloadData card = new CardDownloadData("Emblem " + params[3], set, "0", false, type, "", "", true);
list.add(card); list.add(card);
} else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM-:")) { } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM-:")) {
String set = params[2].substring(8); String set = params[2].substring(8);
CardDownloadData card = new CardDownloadData(params[3] + " Emblem", set, "0", false, type, "", true); CardDownloadData card = new CardDownloadData(params[3] + " Emblem", set, "0", false, type, "", "", true);
list.add(card); list.add(card);
} else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM!:")) { } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM!:")) {
String set = params[2].substring(8); String set = params[2].substring(8);
CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", true); CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true);
list.add(card); list.add(card);
} }
} else { } else {

View file

@ -47,7 +47,7 @@ public class ImageCache {
/** /**
* Common pattern for keys. Format: "<cardname>#<setname>#<collectorID>" * Common pattern for keys. Format: "<cardname>#<setname>#<collectorID>"
*/ */
private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)"); private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)#(.*)");
static { static {
IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function<String, BufferedImage>() { IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function<String, BufferedImage>() {
@ -56,12 +56,12 @@ public class ImageCache {
try { try {
boolean usesVariousArt = false; boolean usesVariousArt = false;
if (key.endsWith("#usesVariousArt")) { if (key.matches(".*#usesVariousArt.*")) {
usesVariousArt = true; usesVariousArt = true;
key = key.replace("#usesVariousArt", ""); key = key.replace("#usesVariousArt", "");
} }
boolean thumbnail = false; boolean thumbnail = false;
if (key.endsWith("#thumb")) { if (key.matches(".*#thumb.*")) {
thumbnail = true; thumbnail = true;
key = key.replace("#thumb", ""); key = key.replace("#thumb", "");
} }
@ -76,8 +76,9 @@ public class ImageCache {
collectorId = "0"; collectorId = "0";
} }
String tokenSetCode = m.group(5); String tokenSetCode = m.group(5);
String tokenDescriptor = m.group(6);
CardDownloadData info = new CardDownloadData(name, set, collectorId, usesVariousArt, type, tokenSetCode); CardDownloadData info = new CardDownloadData(name, set, collectorId, usesVariousArt, type, tokenSetCode, tokenDescriptor);
String path; String path;
if (collectorId.isEmpty() || "0".equals(collectorId)) { if (collectorId.isEmpty() || "0".equals(collectorId)) {
@ -154,7 +155,7 @@ public class ImageCache {
} }
public static BufferedImage getMorphImage() { public static BufferedImage getMorphImage() {
CardDownloadData info = new CardDownloadData("Morph", "KTK", "0", false, 0, "KTK"); CardDownloadData info = new CardDownloadData("Morph", "KTK", "0", false, 0, "KTK", "");
info.setToken(true); info.setToken(true);
String path = CardImageUtils.generateTokenImagePath(info); String path = CardImageUtils.generateTokenImagePath(info);
if (path == null) { if (path == null) {
@ -165,7 +166,7 @@ public class ImageCache {
} }
public static BufferedImage getManifestImage() { public static BufferedImage getManifestImage() {
CardDownloadData info = new CardDownloadData("Manifest", "FRF", "0", false, 0, "FRF"); CardDownloadData info = new CardDownloadData("Manifest", "FRF", "0", false, 0, "FRF", "");
info.setToken(true); info.setToken(true);
String path = CardImageUtils.generateTokenImagePath(info); String path = CardImageUtils.generateTokenImagePath(info);
if (path == null) { if (path == null) {
@ -238,8 +239,8 @@ public class ImageCache {
return name + "#" + card.getExpansionSetCode() + "#" + card.getType() + "#" + card.getCardNumber() + "#" return name + "#" + card.getExpansionSetCode() + "#" + card.getType() + "#" + card.getCardNumber() + "#"
+ (card.getTokenSetCode() == null ? "" : card.getTokenSetCode()) + (card.getTokenSetCode() == null ? "" : card.getTokenSetCode())
+ suffix + suffix
+ (card.getUsesVariousArt() ? "#usesVariousArt" : ""); + (card.getUsesVariousArt() ? "#usesVariousArt" : "")
+ (card.getTokenDescriptor() != null ? "#" + card.getTokenDescriptor() : "#");
} }
// /** // /**

View file

@ -42,7 +42,7 @@ public class CardImageUtils {
return filePath; return filePath;
} }
} }
log.warn("Token image file not found: " + card.getTokenSetCode() + " - " + card.getName()); log.warn("Token image file not found: " + card.getTokenSetCode() + " - " + card.getName());
return null; return null;
} }
@ -50,6 +50,11 @@ public class CardImageUtils {
String filename = generateImagePath(card); String filename = generateImagePath(card);
TFile file = new TFile(filename); TFile file = new TFile(filename);
if (!file.exists()) {
filename = generateTokenDescriptorImagePath(card);
}
file = new TFile(filename);
if (!file.exists()) { if (!file.exists()) {
CardDownloadData updated = new CardDownloadData(card); CardDownloadData updated = new CardDownloadData(card);
updated.setName(card.getName() + " 1"); updated.setName(card.getName() + " 1");
@ -86,7 +91,7 @@ public class CardImageUtils {
// return path; // return path;
// } // }
// } // }
return ""; return generateTokenDescriptorImagePath(card);
} }
public static String updateSet(String cardSet, boolean forUrl) { public static String updateSet(String cardSet, boolean forUrl) {
@ -102,17 +107,28 @@ public class CardImageUtils {
private static String getImageDir(CardDownloadData card, String imagesPath) { private static String getImageDir(CardDownloadData card, String imagesPath) {
if (card.getSet() == null) { if (card.getSet() == null) {
return ""; return "";
} }
String set = updateSet(card.getSet(), false).toUpperCase(); String set = updateSet(card.getSet(), false).toUpperCase();
String imagesDir = (imagesPath != null ? imagesPath : Constants.IO.imageBaseDir); String imagesDir = (imagesPath != null ? imagesPath : Constants.IO.imageBaseDir);
if (card.isToken()) { if (card.isToken()) {
return buildTokenPath(imagesDir, set); return buildTokenPath(imagesDir, set);
} else { } else {
return buildPath(imagesDir, set); return buildPath(imagesDir, set);
} }
} }
private static String getTokenDescriptorImagePath(CardDownloadData card) {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String imagesPath = useDefault.equals("true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
if (PreferencesDialog.isSaveImagesToZip()) {
return imagesPath + TFile.separator + "TOK" + ".zip" + TFile.separator + card.getTokenDescriptor() + ".full.jpg";
} else {
return imagesPath + TFile.separator + "TOK" + TFile.separator + card.getTokenDescriptor() + ".full.jpg";
}
}
private static String buildTokenPath(String imagesDir, String set) { private static String buildTokenPath(String imagesDir, String set) {
if (PreferencesDialog.isSaveImagesToZip()) { if (PreferencesDialog.isSaveImagesToZip()) {
return imagesDir + TFile.separator + "TOK" + ".zip" + TFile.separator + set; return imagesDir + TFile.separator + "TOK" + ".zip" + TFile.separator + set;
@ -156,7 +172,31 @@ public class CardImageUtils {
return imageDir + TFile.separator + imageName; return imageDir + TFile.separator + imageName;
} }
public static String generateTokenDescriptorImagePath(CardDownloadData card) {
String useDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_USE_DEFAULT, "true");
String imagesPath = useDefault.equals("true") ? null : PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PATH, null);
String straightImageFile = getTokenDescriptorImagePath(card);
TFile file = new TFile(straightImageFile);
if (file.exists()) {
return straightImageFile;
}
straightImageFile = straightImageFile.replaceFirst("\\.[0-9]+\\.[0-9]+", ".X.X");
file = new TFile(straightImageFile);
if (file.exists()) {
return straightImageFile;
}
straightImageFile = straightImageFile.replaceFirst("\\.X\\.X", ".S.S");
file = new TFile(straightImageFile);
if (file.exists()) {
return straightImageFile;
}
return "";
}
public static Proxy getProxyFromPreferences() { public static Proxy getProxyFromPreferences() {
Preferences prefs = MageFrame.getPreferences(); Preferences prefs = MageFrame.getPreferences();
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None")); Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None"));

View file

@ -18,15 +18,15 @@ public class TokensMtgImageSourceTest {
public void generateTokenUrlTest() throws Exception { public void generateTokenUrlTest() throws Exception {
CardImageSource imageSource = TokensMtgImageSource.getInstance(); CardImageSource imageSource = TokensMtgImageSource.getInstance();
String url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI")); String url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url); Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url);
url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 2, "ORI")); url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 2, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url); Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url);
url = imageSource.generateTokenUrl(new CardDownloadData("Ashaya, the Awoken World", "ORI", "0", false, 0, "ORI")); url = imageSource.generateTokenUrl(new CardDownloadData("Ashaya, the Awoken World", "ORI", "0", false, 0, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url); Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url);
url = imageSource.generateTokenUrl(new CardDownloadData("Emblem Gideon, Ally of Zendikar", "BFZ", "0", false, 0, null)); url = imageSource.generateTokenUrl(new CardDownloadData("Emblem Gideon, Ally of Zendikar", "BFZ", "0", false, 0, null, ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url); Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url);
} }
} }

View file

@ -159,7 +159,7 @@ public class CardView extends SimpleCardView {
* @param storeZone if true the card zone will be set in the zone attribute. * @param storeZone if true the card zone will be set in the zone attribute.
*/ */
public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) { public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) {
super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null); super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null, card.getTokenDescriptor());
// no information available for face down cards as long it's not a controlled face down morph card // no information available for face down cards as long it's not a controlled face down morph card
// TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2 // TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2
boolean showFaceUp = true; boolean showFaceUp = true;
@ -291,6 +291,7 @@ public class CardView extends SimpleCardView {
} else { } else {
// a created token // a created token
this.expansionSetCode = ((PermanentToken) card).getExpansionSetCode(); this.expansionSetCode = ((PermanentToken) card).getExpansionSetCode();
this.tokenDescriptor = ((PermanentToken) card).getTokenDescriptor();
} }
// //
// set code und card number for token copies to get the image // set code und card number for token copies to get the image
@ -332,7 +333,7 @@ public class CardView extends SimpleCardView {
} }
public CardView(MageObject object) { public CardView(MageObject object) {
super(object.getId(), "", "0", false, "", true); super(object.getId(), "", "0", false, "", true, "");
this.name = object.getName(); this.name = object.getName();
this.displayName = object.getName(); this.displayName = object.getName();
if (object instanceof Permanent) { if (object instanceof Permanent) {
@ -376,7 +377,7 @@ public class CardView extends SimpleCardView {
} }
protected CardView() { protected CardView() {
super(null, "", "0", false, "", true); super(null, "", "0", false, "", true, "");
} }
public CardView(EmblemView emblem) { public CardView(EmblemView emblem) {
@ -393,7 +394,7 @@ public class CardView extends SimpleCardView {
} }
public CardView(boolean empty) { public CardView(boolean empty) {
super(null, "", "0", false, ""); super(null, "", "0", false, "", "");
if (!empty) { if (!empty) {
throw new IllegalArgumentException("Not supported."); throw new IllegalArgumentException("Not supported.");
} }
@ -442,7 +443,7 @@ public class CardView extends SimpleCardView {
} }
CardView(Token token) { CardView(Token token) {
super(token.getId(), "", "0", false, ""); super(token.getId(), "", "0", false, "", "");
this.isToken = true; this.isToken = true;
this.id = token.getId(); this.id = token.getId();
this.name = token.getName(); this.name = token.getName();
@ -459,6 +460,7 @@ public class CardView extends SimpleCardView {
this.rarity = Rarity.NA; this.rarity = Rarity.NA;
this.type = token.getTokenType(); this.type = token.getTokenType();
this.tokenSetCode = token.getOriginalExpansionSetCode(); this.tokenSetCode = token.getOriginalExpansionSetCode();
this.tokenDescriptor = token.getTokenDescriptor();
} }
protected final void setTargets(Targets targets) { protected final void setTargets(Targets targets) {

View file

@ -46,7 +46,7 @@ public class LookedAtView implements Serializable {
public LookedAtView(String name, Cards cards, Game game) { public LookedAtView(String name, Cards cards, Game game) {
this.name = name; this.name = name;
for (Card card: cards.getCards(game)) { for (Card card: cards.getCards(game)) {
this.cards.put(card.getId(), new SimpleCardView(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode())); this.cards.put(card.getId(), new SimpleCardView(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), card.getTokenDescriptor()));
} }
} }

View file

@ -81,6 +81,7 @@ public class PermanentView extends CardView {
original = new CardView(((PermanentToken) permanent).getToken()); original = new CardView(((PermanentToken) permanent).getToken());
original.expansionSetCode = permanent.getExpansionSetCode(); original.expansionSetCode = permanent.getExpansionSetCode();
tokenSetCode = original.getTokenSetCode(); tokenSetCode = original.getTokenSetCode();
tokenDescriptor = original.getTokenDescriptor();
} else { } else {
if (card != null) { if (card != null) {
// original may not be face down // original may not be face down

View file

@ -39,16 +39,18 @@ public class SimpleCardView implements Serializable {
protected UUID id; protected UUID id;
protected String expansionSetCode; protected String expansionSetCode;
protected String tokenSetCode; protected String tokenSetCode;
protected String tokenDescriptor;
protected String cardNumber; protected String cardNumber;
protected boolean usesVariousArt; protected boolean usesVariousArt;
protected boolean gameObject; protected boolean gameObject;
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode) { public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, String tokenDescriptor) {
this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false); this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false, tokenDescriptor);
} }
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, boolean isGameObject) { public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, boolean isGameObject, String tokenDescriptor) {
this.id = id; this.id = id;
this.expansionSetCode = expansionSetCode; this.expansionSetCode = expansionSetCode;
this.tokenDescriptor = tokenDescriptor;
this.cardNumber = cardNumber; this.cardNumber = cardNumber;
this.usesVariousArt = usesVariousArt; this.usesVariousArt = usesVariousArt;
this.tokenSetCode = tokenSetCode; this.tokenSetCode = tokenSetCode;
@ -74,6 +76,10 @@ public class SimpleCardView implements Serializable {
public String getTokenSetCode() { public String getTokenSetCode() {
return tokenSetCode; return tokenSetCode;
} }
public String getTokenDescriptor() {
return tokenDescriptor;
}
public boolean isGameObject() { public boolean isGameObject() {
return gameObject; return gameObject;

View file

@ -44,7 +44,8 @@ public class SimpleCardsView extends LinkedHashMap<UUID, SimpleCardView> {
public SimpleCardsView(Collection<Card> cards, boolean isGameObject) { public SimpleCardsView(Collection<Card> cards, boolean isGameObject) {
for (Card card: cards) { for (Card card: cards) {
this.put(card.getId(), new SimpleCardView(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), isGameObject)); this.put(card.getId(), new SimpleCardView(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), isGameObject,
card.getTokenDescriptor()));
} }
} }

View file

@ -31,13 +31,13 @@ import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility;
import mage.abilities.condition.common.OneControlledCreatureCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.game.permanent.token.DemonToken; import mage.game.permanent.token.DemonToken;
import java.util.UUID; import java.util.UUID;
import mage.abilities.condition.common.CreatureCountCondition;
import mage.constants.TargetController;
/** /**
* @author noxx * @author noxx
@ -52,7 +52,7 @@ public class DemonicRising extends CardImpl {
// At the beginning of your end step, if you control exactly one creature, put a 5/5 black Demon creature token with flying onto the battlefield. // At the beginning of your end step, if you control exactly one creature, put a 5/5 black Demon creature token with flying onto the battlefield.
TriggeredAbility ability = new BeginningOfYourEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken()), false); TriggeredAbility ability = new BeginningOfYourEndStepTriggeredAbility(new CreateTokenEffect(new DemonToken()), false);
this.addAbility(new ConditionalTriggeredAbility(ability, OneControlledCreatureCondition.getInstance(), ruleText)); this.addAbility(new ConditionalTriggeredAbility(ability, new CreatureCountCondition(1, TargetController.YOU), ruleText));
} }
public DemonicRising(final DemonicRising card) { public DemonicRising(final DemonicRising card) {

View file

@ -30,7 +30,7 @@ package mage.sets.avacynrestored;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.OneControlledCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
@ -41,6 +41,7 @@ import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
/** /**
@ -56,10 +57,10 @@ public class HomicidalSeclusion extends CardImpl {
// As long as you control exactly one creature, that creature gets +3/+1 and has lifelink. // As long as you control exactly one creature, that creature gets +3/+1 and has lifelink.
ContinuousEffect boostEffect = new BoostControlledEffect(3, 1, Duration.WhileOnBattlefield); ContinuousEffect boostEffect = new BoostControlledEffect(3, 1, Duration.WhileOnBattlefield);
Effect effect = new ConditionalContinuousEffect(boostEffect, new OneControlledCreatureCondition(), rule); Effect effect = new ConditionalContinuousEffect(boostEffect, new CreatureCountCondition(1, TargetController.YOU), rule);
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
ContinuousEffect lifelinkEffect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield); ContinuousEffect lifelinkEffect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield);
effect = new ConditionalContinuousEffect(lifelinkEffect, new OneControlledCreatureCondition(), "and has lifelink"); effect = new ConditionalContinuousEffect(lifelinkEffect, new CreatureCountCondition(1, TargetController.YOU), "and has lifelink");
ability.addEffect(effect); ability.addEffect(effect);
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -30,7 +30,6 @@ package mage.sets.avacynrestored;
import mage.constants.*; import mage.constants.*;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.OneControlledCreatureCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
@ -41,8 +40,8 @@ import mage.abilities.keyword.IntimidateAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID; import java.util.UUID;
import mage.abilities.condition.common.CreatureCountCondition;
/** /**
* @author noxx * @author noxx
@ -56,7 +55,6 @@ public class PredatorsGambit extends CardImpl {
this.expansionSetCode = "AVR"; this.expansionSetCode = "AVR";
this.subtype.add("Aura"); this.subtype.add("Aura");
// Enchant creature // Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent(); TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);
@ -70,7 +68,7 @@ public class PredatorsGambit extends CardImpl {
// Enchanted creature has intimidate as long as its controller controls no other creatures. // Enchanted creature has intimidate as long as its controller controls no other creatures.
ContinuousEffect effect = new GainAbilityAttachedEffect(IntimidateAbility.getInstance(), AttachmentType.AURA); ContinuousEffect effect = new GainAbilityAttachedEffect(IntimidateAbility.getInstance(), AttachmentType.AURA);
ConditionalContinuousEffect intimidate = new ConditionalContinuousEffect(effect, new OneControlledCreatureCondition(), rule); ConditionalContinuousEffect intimidate = new ConditionalContinuousEffect(effect, new CreatureCountCondition(1, TargetController.YOU), rule);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, intimidate)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, intimidate));
} }

View file

@ -43,7 +43,7 @@ import mage.filter.common.FilterControlledPermanent;
*/ */
public class AkkiBlizzardHerder extends CardImpl { public class AkkiBlizzardHerder extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); private static final FilterControlledPermanent filter = new FilterControlledLandPermanent("land");
public AkkiBlizzardHerder(UUID ownerId) { public AkkiBlizzardHerder(UUID ownerId) {
super(ownerId, 91, "Akki Blizzard-Herder", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); super(ownerId, 91, "Akki Blizzard-Herder", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}");

View file

@ -28,19 +28,13 @@
package mage.sets.bornofthegods; package mage.sets.bornofthegods;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
/** /**
@ -49,11 +43,10 @@ import mage.target.TargetPermanent;
*/ */
public class UnravelTheAEther extends CardImpl { public class UnravelTheAEther extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(); private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment");
static { static {
filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.ENCHANTMENT)));
new CardTypePredicate(CardType.ENCHANTMENT)));
} }
public UnravelTheAEther(UUID ownerId) { public UnravelTheAEther(UUID ownerId) {
@ -61,9 +54,8 @@ public class UnravelTheAEther extends CardImpl {
this.expansionSetCode = "BNG"; this.expansionSetCode = "BNG";
// Choose target artifact or enchantment. Its owner shuffles it into his or her library. // Choose target artifact or enchantment. Its owner shuffles it into his or her library.
this.getSpellAbility().addEffect(new UnravelTheAEtherShuffleIntoLibraryEffect()); this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect());
Target target = new TargetPermanent(1, 1, filter, false); this.getSpellAbility().addTarget(new TargetPermanent(1, 1, filter, true));
this.getSpellAbility().addTarget(target);
} }
public UnravelTheAEther(final UnravelTheAEther card) { public UnravelTheAEther(final UnravelTheAEther card) {
@ -75,32 +67,3 @@ public class UnravelTheAEther extends CardImpl {
return new UnravelTheAEther(this); return new UnravelTheAEther(this);
} }
} }
class UnravelTheAEtherShuffleIntoLibraryEffect extends OneShotEffect {
public UnravelTheAEtherShuffleIntoLibraryEffect() {
super(Outcome.Detriment);
this.staticText = "Choose target artifact or enchantment. Its owner shuffles it into his or her library";
}
public UnravelTheAEtherShuffleIntoLibraryEffect(final UnravelTheAEtherShuffleIntoLibraryEffect effect) {
super(effect);
}
@Override
public UnravelTheAEtherShuffleIntoLibraryEffect copy() {
return new UnravelTheAEtherShuffleIntoLibraryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
if (permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true)) {
game.getPlayer(permanent.getOwnerId()).shuffleLibrary(source, game);
return true;
}
}
return false;
}
}

View file

@ -52,8 +52,8 @@ public class RyuseiTheFallingStar extends CardImpl {
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
} }
public RyuseiTheFallingStar(UUID ownerID) { public RyuseiTheFallingStar(UUID ownerId) {
super(ownerID, 185, "Ryusei, the Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); super(ownerId, 185, "Ryusei, the Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}");
this.expansionSetCode = "CHK"; this.expansionSetCode = "CHK";
this.supertype.add("Legendary"); this.supertype.add("Legendary");
this.subtype.add("Dragon"); this.subtype.add("Dragon");

View file

@ -28,26 +28,21 @@
package mage.sets.commander2014; package mage.sets.commander2014;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.common.CanBeYourCommanderAbility;
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.UntapTargetEffect;
import mage.abilities.effects.common.continuous.ActivateAbilitiesAnyTimeYouCouldCastInstantEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
@ -96,42 +91,6 @@ class TeferiTemporalArchmageEmblem extends Emblem {
// "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant." // "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant."
public TeferiTemporalArchmageEmblem() { public TeferiTemporalArchmageEmblem() {
this.setName("EMBLEM: Teferi, Temporal Archmage"); this.setName("EMBLEM: Teferi, Temporal Archmage");
this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new TeferiTemporalArchmageAsThoughEffect())); this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(LoyaltyAbility.class, "loyalty abilities of planeswalkers you control on any player's turn")));
} }
} }
class TeferiTemporalArchmageAsThoughEffect extends AsThoughEffectImpl {
public TeferiTemporalArchmageAsThoughEffect() {
super(AsThoughEffectType.ACTIVATE_AS_INSTANT, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant";
}
public TeferiTemporalArchmageAsThoughEffect(final TeferiTemporalArchmageAsThoughEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public TeferiTemporalArchmageAsThoughEffect copy() {
return new TeferiTemporalArchmageAsThoughEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) {
if (affectedAbility.getControllerId().equals(source.getControllerId()) && affectedAbility instanceof LoyaltyAbility) {
return true;
}
return false;
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return false; // Not used
}
}

View file

@ -29,18 +29,13 @@ package mage.sets.darksteel;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.continuous.ActivateAbilitiesAnyTimeYouCouldCastInstantEffect;
import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
/** /**
* *
@ -57,7 +52,7 @@ public class LeoninShikari extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// You may activate equip abilities any time you could cast an instant. // You may activate equip abilities any time you could cast an instant.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LeoninShikariEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(EquipAbility.class, "equip abilities")));
} }
public LeoninShikari(final LeoninShikari card) { public LeoninShikari(final LeoninShikari card) {
@ -69,35 +64,3 @@ public class LeoninShikari extends CardImpl {
return new LeoninShikari(this); return new LeoninShikari(this);
} }
} }
class LeoninShikariEffect extends AsThoughEffectImpl {
LeoninShikariEffect() {
super(AsThoughEffectType.ACTIVATE_AS_INSTANT, Duration.EndOfGame, Outcome.Benefit);
staticText = "You may activate equip abilities any time you could cast an instant";
}
LeoninShikariEffect(final LeoninShikariEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public LeoninShikariEffect copy() {
return new LeoninShikariEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) {
return affectedAbility.getControllerId().equals(source.getControllerId()) && affectedAbility instanceof EquipAbility;
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return false; // Not used
}
}

View file

@ -30,7 +30,7 @@ package mage.sets.dragonsoftarkir;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.OneControlledCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
@ -42,6 +42,7 @@ import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
@ -57,14 +58,16 @@ public class DeadlyWanderings extends CardImpl {
// As long as you control exactly one creature, that creature gets +2/+0 and has deathtouch and lifelink. // As long as you control exactly one creature, that creature gets +2/+0 and has deathtouch and lifelink.
ContinuousEffect boostEffect = new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield); ContinuousEffect boostEffect = new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield);
Effect effect = new ConditionalContinuousEffect(boostEffect, new OneControlledCreatureCondition(), Effect effect = new ConditionalContinuousEffect(boostEffect, new CreatureCountCondition(1, TargetController.YOU),
"As long as you control exactly one creature, that creature gets +2/+0"); "As long as you control exactly one creature, that creature gets +2/+0");
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
ContinuousEffect deathtouchEffect = new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()); ContinuousEffect deathtouchEffect = new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent());
effect = new ConditionalContinuousEffect(deathtouchEffect, new OneControlledCreatureCondition(), "and has deathtouch"); effect = new ConditionalContinuousEffect(deathtouchEffect, new CreatureCountCondition(1, TargetController.YOU),
"and has deathtouch");
ability.addEffect(effect); ability.addEffect(effect);
ContinuousEffect lifelinkEffect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()); ContinuousEffect lifelinkEffect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent());
effect = new ConditionalContinuousEffect(lifelinkEffect, new OneControlledCreatureCondition(), "and lifelink"); effect = new ConditionalContinuousEffect(lifelinkEffect, new CreatureCountCondition(1, TargetController.YOU),
"and lifelink");
ability.addEffect(effect); ability.addEffect(effect);
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -38,7 +38,7 @@ import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.OneControlledCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.decorator.ConditionalRestrictionEffect;
@ -53,6 +53,7 @@ import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -73,7 +74,7 @@ public class JeskaiInfiltrator extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Jeskai Infiltrator can't be blocked as long as you control no other creatures. // Jeskai Infiltrator can't be blocked as long as you control no other creatures.
Effect effect = new ConditionalRestrictionEffect(new CantBeBlockedSourceEffect(), new OneControlledCreatureCondition()); Effect effect = new ConditionalRestrictionEffect(new CantBeBlockedSourceEffect(), new CreatureCountCondition(1, TargetController.YOU));
effect.setText("{this} can't be blocked as long as you control no other creatures"); effect.setText("{this} can't be blocked as long as you control no other creatures");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));

View file

@ -0,0 +1,97 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.invasion;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author Derpthemeus
*/
public class LightningDart extends CardImpl {
public LightningDart(UUID ownerId) {
super(ownerId, 152, "Lightning Dart", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{R}");
this.expansionSetCode = "INV";
// Lightning Dart deals 1 damage to target creature. If that creature is white or blue, Lightning Dart deals 4 damage to it instead.
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new LightningDartEffect());
}
public LightningDart(final LightningDart card) {
super(card);
}
@Override
public LightningDart copy() {
return new LightningDart(this);
}
class LightningDartEffect extends OneShotEffect {
public LightningDartEffect() {
super(Outcome.Damage);
this.staticText = "Lightning Dart deals 1 damage to target creature. If that creature is white or blue, Lightning Dart deals 4 damage to it instead";
}
public LightningDartEffect(final LightningDartEffect effect) {
super(effect);
}
@Override
public LightningDartEffect copy() {
return new LightningDartEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
int damage = 1;
ObjectColor color = permanent.getColor(game);
if (color.isWhite() || color.isBlue()) {
damage = 4;
}
permanent.damage(damage, source.getId(), game, false, false);
}
return false;
}
}
}

View file

@ -32,7 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.condition.common.NoCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.SacrificeEffect;
import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect;
@ -62,13 +62,12 @@ public class CallToTheGrave extends CardImpl {
super(ownerId, 85, "Call to the Grave", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); super(ownerId, 85, "Call to the Grave", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}");
this.expansionSetCode = "M12"; this.expansionSetCode = "M12";
// At the beginning of each player's upkeep, that player sacrifices a non-Zombie creature. // At the beginning of each player's upkeep, that player sacrifices a non-Zombie creature.
Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeEffect(filter, 1, "that player "), TargetController.ANY, false); Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeEffect(filter, 1, "that player "), TargetController.ANY, false);
this.addAbility(ability); this.addAbility(ability);
// At the beginning of the end step, if no creatures are on the battlefield, sacrifice Call to the Grave. // At the beginning of the end step, if no creatures are on the battlefield, sacrifice Call to the Grave.
TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect());
this.addAbility(new ConditionalTriggeredAbility(triggered, new NoCreatureCondition(), ruleText)); this.addAbility(new ConditionalTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText));
} }
public CallToTheGrave(final CallToTheGrave card) { public CallToTheGrave(final CallToTheGrave card) {

View file

@ -29,7 +29,7 @@ package mage.sets.magic2014;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
@ -45,8 +45,6 @@ import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player; import mage.players.Player;
/** /**
@ -66,12 +64,11 @@ public class PathOfBravery extends CardImpl {
super(ownerId, 26, "Path of Bravery", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); super(ownerId, 26, "Path of Bravery", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
this.expansionSetCode = "M14"; this.expansionSetCode = "M14";
// As long as your life total is greater than or equal to your starting life total, creatures you control get +1/+1. // As long as your life total is greater than or equal to your starting life total, creatures you control get +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true), new LifeCondition(), rule))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true), new LifeCondition(), rule)));
// Whenever one or more creatures you control attack, you gain life equal to the number of attacking creatures. // Whenever one or more creatures you control attack, you gain life equal to the number of attacking creatures.
this.addAbility(new PathOfBraveryTriggeredAbility()); this.addAbility(new AttacksWithCreaturesTriggeredAbility(new PathOfBraveryEffect(), 1));
} }
@ -103,37 +100,6 @@ class LifeCondition implements Condition {
} }
} }
class PathOfBraveryTriggeredAbility extends TriggeredAbilityImpl {
public PathOfBraveryTriggeredAbility() {
super(Zone.BATTLEFIELD, new PathOfBraveryEffect(), false);
}
public PathOfBraveryTriggeredAbility(final PathOfBraveryTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return !game.getCombat().noAttackers() && event.getPlayerId().equals(controllerId);
}
@Override
public PathOfBraveryTriggeredAbility copy() {
return new PathOfBraveryTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever one or more creatures you control attack, " + super.getRule();
}
}
class PathOfBraveryEffect extends OneShotEffect { class PathOfBraveryEffect extends OneShotEffect {
private int attackers; private int attackers;

View file

@ -28,16 +28,11 @@
package mage.sets.magic2015; package mage.sets.magic2015;
import java.util.UUID; import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
/** /**
* *
@ -49,9 +44,8 @@ public class MilitaryIntelligence extends CardImpl {
super(ownerId, 69, "Military Intelligence", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); super(ownerId, 69, "Military Intelligence", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
this.expansionSetCode = "M15"; this.expansionSetCode = "M15";
// Whenever you attack with two or more creatures, draw a card. // Whenever you attack with two or more creatures, draw a card.
this.addAbility(new MilitaryIntelligenceTriggeredAbility(new DrawCardSourceControllerEffect(1))); this.addAbility(new AttacksWithCreaturesTriggeredAbility(new DrawCardSourceControllerEffect(1), 2));
} }
public MilitaryIntelligence(final MilitaryIntelligence card) { public MilitaryIntelligence(final MilitaryIntelligence card) {
@ -63,34 +57,3 @@ public class MilitaryIntelligence extends CardImpl {
return new MilitaryIntelligence(this); return new MilitaryIntelligence(this);
} }
} }
class MilitaryIntelligenceTriggeredAbility extends TriggeredAbilityImpl {
public MilitaryIntelligenceTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect);
}
public MilitaryIntelligenceTriggeredAbility(final MilitaryIntelligenceTriggeredAbility ability) {
super(ability);
}
@Override
public MilitaryIntelligenceTriggeredAbility copy() {
return new MilitaryIntelligenceTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return game.getCombat().getAttackers().size() >= 2 && game.getCombat().getAttackerId().equals(getControllerId());
}
@Override
public String getRule() {
return new StringBuilder("Whenever you attack with two or more creatures, ").append(super.getRule()).toString() ;
}
}

View file

@ -1,58 +1,59 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.condition.common; package mage.sets.mercadianmasques;
import mage.abilities.Ability; import java.util.UUID;
import mage.abilities.condition.Condition; import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.filter.common.FilterCreaturePermanent; import mage.abilities.effects.common.GainLifeEffect;
import mage.game.Game; import mage.cards.CardImpl;
import mage.constants.CardType;
/** import mage.constants.Rarity;
* @author noxx
*/ /**
public class OneControlledCreatureCondition implements Condition { *
* @author Derpthemeus
private static final OneControlledCreatureCondition fInstance = new OneControlledCreatureCondition(); */
public class MoonlitWake extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
public MoonlitWake(UUID ownerId) {
public static Condition getInstance() { super(ownerId, 29, "Moonlit Wake", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
return fInstance; this.expansionSetCode = "MMQ";
}
// Whenever a creature dies, you gain 1 life.
@Override this.addAbility(new DiesCreatureTriggeredAbility(new GainLifeEffect(1), false));
public boolean apply(Game game, Ability source) { }
return game.getBattlefield().countAll(filter, source.getControllerId(), game) == 1;
} public MoonlitWake(final MoonlitWake card) {
super(card);
@Override }
public String toString() {
return "you control exactly one creature"; @Override
} public MoonlitWake copy() {
return new MoonlitWake(this);
} }
}

View file

@ -0,0 +1,74 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.mirage;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
/**
*
* @author Derpthemeus
*/
public class ElixirOfVitality extends CardImpl {
public ElixirOfVitality(UUID ownerId) {
super(ownerId, 265, "Elixir of Vitality", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{4}");
this.expansionSetCode = "MIR";
// Elixir of Vitality enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// {tap}, Sacrifice Elixir of Vitality: You gain 4 life.
Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(4), new TapSourceCost());
ability1.addCost(new SacrificeSourceCost());
this.addAbility(ability1);
// {8}, {tap}, Sacrifice Elixir of Vitality: You gain 8 life.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(8), new ManaCostsImpl("{8}"));
ability2.addCost(new TapSourceCost());
ability2.addCost(new SacrificeSourceCost());
this.addAbility(ability2);
}
public ElixirOfVitality(final ElixirOfVitality card) {
super(card);
}
@Override
public ElixirOfVitality copy() {
return new ElixirOfVitality(this);
}
}

View file

@ -29,27 +29,25 @@ package mage.sets.mirrodin;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.EquippedSourceCondition; import mage.abilities.condition.common.EquippedSourceCondition;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.cost.AbilitiesCostReductionControllerEffect;
import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.EquipAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.Game;
import mage.util.CardUtil;
/** /**
* *
* @author Jason E. Wall * @author Jason E. Wall
*
*/ */
public class AuriokSteelshaper extends CardImpl { public class AuriokSteelshaper extends CardImpl {
private static final FilterCreaturePermanent soldiersOrKnights = new FilterCreaturePermanent(); private static final FilterCreaturePermanent soldiersOrKnights = new FilterCreaturePermanent();
static { static {
@ -68,7 +66,7 @@ public class AuriokSteelshaper extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Equip costs you pay cost {1} less. // Equip costs you pay cost {1} less.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AuriokSteelshaperCostReductionEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AbilitiesCostReductionControllerEffect(EquipAbility.class, "Equip")));
// As long as Auriok Steelshaper is equipped, each creature you control that's a Soldier or a Knight gets +1/+1. // As long as Auriok Steelshaper is equipped, each creature you control that's a Soldier or a Knight gets +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
@ -87,32 +85,3 @@ public class AuriokSteelshaper extends CardImpl {
return new AuriokSteelshaper(this); return new AuriokSteelshaper(this);
} }
} }
class AuriokSteelshaperCostReductionEffect extends CostModificationEffectImpl {
public AuriokSteelshaperCostReductionEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "Equip costs you pay cost {1} less";
}
public AuriokSteelshaperCostReductionEffect(AuriokSteelshaperCostReductionEffect effect) {
super(effect);
}
@java.lang.Override
public AuriokSteelshaperCostReductionEffect copy() {
return new AuriokSteelshaperCostReductionEffect(this);
}
@java.lang.Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.reduceCost(abilityToModify, 1);
return true;
}
@java.lang.Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify.getControllerId().equals(source.getControllerId()) &&
(abilityToModify instanceof EquipAbility);
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.mirrodin;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.EquippedSourceCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
/**
*
* @author Derpthemeus
*/
public class SkyhunterCub extends CardImpl {
private static final String rule1 = "As long as {this} is equipped, it gets +1/+1";
private static final String rule2 = "As long as {this} is equipped, it has flying";
public SkyhunterCub(UUID ownerId) {
super(ownerId, 21, "Skyhunter Cub", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.expansionSetCode = "MRD";
this.subtype.add("Cat");
this.subtype.add("Knight");
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// As long as Skyhunter Cub is equipped, it gets +1/+1 and has flying.
ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), EquippedSourceCondition.getInstance(), rule1);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect1));
ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), EquippedSourceCondition.getInstance(), rule2);
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2));
}
public SkyhunterCub(final SkyhunterCub card) {
super(card);
}
@java.lang.Override
public SkyhunterCub copy() {
return new SkyhunterCub(this);
}
}

View file

@ -29,18 +29,12 @@ package mage.sets.morningtide;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone; import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
/** /**
@ -49,21 +43,18 @@ import mage.target.TargetPermanent;
*/ */
public class Deglamer extends CardImpl { public class Deglamer extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(); private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment");
static { static {
filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.ENCHANTMENT)));
new CardTypePredicate(CardType.ENCHANTMENT)));
} }
public Deglamer(UUID ownerId) { public Deglamer(UUID ownerId) {
super(ownerId, 118, "Deglamer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); super(ownerId, 118, "Deglamer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}");
this.expansionSetCode = "MOR"; this.expansionSetCode = "MOR";
// Choose target artifact or enchantment. Its owner shuffles it into his or her library. // Choose target artifact or enchantment. Its owner shuffles it into his or her library.
this.getSpellAbility().addEffect(new DeglamerShuffleIntoLibraryEffect()); this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect());
Target target = new TargetPermanent(1,1,filter,true); this.getSpellAbility().addTarget(new TargetPermanent(1, 1, filter, true));
this.getSpellAbility().addTarget(target);
} }
public Deglamer(final Deglamer card) { public Deglamer(final Deglamer card) {
@ -74,33 +65,4 @@ public class Deglamer extends CardImpl {
public Deglamer copy() { public Deglamer copy() {
return new Deglamer(this); return new Deglamer(this);
} }
} }
class DeglamerShuffleIntoLibraryEffect extends OneShotEffect {
public DeglamerShuffleIntoLibraryEffect() {
super(Outcome.Detriment);
this.staticText = "Choose target artifact or enchantment. Its owner shuffles it into his or her library";
}
public DeglamerShuffleIntoLibraryEffect(final DeglamerShuffleIntoLibraryEffect effect) {
super(effect);
}
@Override
public DeglamerShuffleIntoLibraryEffect copy() {
return new DeglamerShuffleIntoLibraryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
if (permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true) ) {
game.getPlayer(permanent.getOwnerId()).shuffleLibrary(source, game);
return true;
}
}
return false;
}
}

View file

@ -53,8 +53,8 @@ import mage.target.common.TargetOpponent;
*/ */
public class AnimalMagnetism extends CardImpl { public class AnimalMagnetism extends CardImpl {
public AnimalMagnetism(UUID ownerID) { public AnimalMagnetism(UUID ownerId) {
super(ownerID, 245, "Animal Magnetism", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{G}"); super(ownerId, 245, "Animal Magnetism", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{G}");
this.expansionSetCode = "ONS"; this.expansionSetCode = "ONS";
// Reveal the top five cards of your library. An opponent chooses a creature card from among them. Put that card onto the battlefield and the rest into your graveyard. // Reveal the top five cards of your library. An opponent chooses a creature card from among them. Put that card onto the battlefield and the rest into your graveyard.

View file

@ -45,8 +45,8 @@ import mage.watchers.common.AttackedThisTurnWatcher;
*/ */
public class GrandMelee extends CardImpl { public class GrandMelee extends CardImpl {
public GrandMelee(UUID ownerID) { public GrandMelee(UUID ownerId) {
super(ownerID, 211, "Grand Melee", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); super(ownerId, 211, "Grand Melee", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}");
this.expansionSetCode = "ONS"; this.expansionSetCode = "ONS";
// All creatures attack each turn if able. // All creatures attack each turn if able.

View file

@ -95,7 +95,9 @@ class GratuitousViolenceReplacementEffect extends ReplacementEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
return permanent != null && permanent.getControllerId().equals(source.getControllerId()); return permanent != null
&& permanent.getCardType().contains(CardType.CREATURE)
&& permanent.getControllerId().equals(source.getControllerId());
} }
@Override @Override

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.onslaught;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterEnchantmentPermanent;
/**
*
* @author Derpthemeus
*/
public class NovaCleric extends CardImpl {
public NovaCleric(UUID ownerId) {
super(ownerId, 45, "Nova Cleric", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{W}");
this.expansionSetCode = "ONS";
this.subtype.add("Human");
this.subtype.add("Cleric");
this.power = new MageInt(1);
this.toughness = new MageInt(2);
// {2}{W}, {tap}, Sacrifice Nova Cleric: Destroy all enchantments.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyAllEffect(new FilterEnchantmentPermanent("enchantments")), new ManaCostsImpl("{2}{W}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
public NovaCleric(final NovaCleric card) {
super(card);
}
@Override
public NovaCleric copy() {
return new NovaCleric(this);
}
}

View file

@ -31,7 +31,7 @@ import java.util.UUID;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.NoCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.DamageEverythingEffect;
@ -39,6 +39,7 @@ import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -47,7 +48,7 @@ import mage.game.events.GameEvent;
* @author fireshoes * @author fireshoes
*/ */
public class Pyrohemia extends CardImpl { public class Pyrohemia extends CardImpl {
private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pyrohemia."; private static final String ruleText = "At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pyrohemia.";
public Pyrohemia(UUID ownerId) { public Pyrohemia(UUID ownerId) {
@ -56,8 +57,8 @@ public class Pyrohemia extends CardImpl {
// At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pyrohemia. // At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pyrohemia.
TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect());
this.addAbility(new ConditionalTriggeredAbility(triggered, new NoCreatureCondition(), ruleText)); this.addAbility(new ConditionalTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText));
// {R}: Pyrohemia deals 1 damage to each creature and each player. // {R}: Pyrohemia deals 1 damage to each creature and each player.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{R}"))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{R}")));
} }

View file

@ -58,8 +58,8 @@ import mage.watchers.common.CastFromHandWatcher;
*/ */
public class WildPair extends CardImpl { public class WildPair extends CardImpl {
public WildPair(UUID ownerID) { public WildPair(UUID ownerId) {
super(ownerID, 144, "Wild Pair", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); super(ownerId, 144, "Wild Pair", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}");
this.expansionSetCode = "PLC"; this.expansionSetCode = "PLC";
// Whenever a creature enters the battlefield, if you cast it from your hand, you may search your library for a creature card with the same total power and toughness and put it onto the battlefield. If you do, shuffle your library. // Whenever a creature enters the battlefield, if you cast it from your hand, you may search your library for a creature card with the same total power and toughness and put it onto the battlefield. If you do, shuffle your library.

View file

@ -0,0 +1,113 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.planeshift;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.choices.ChoiceColor;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterEnchantmentPermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author Derpthemeus
*/
public class RootGreevil extends CardImpl {
public RootGreevil(UUID ownerId) {
super(ownerId, 91, "Root Greevil", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{3}{G}");
this.expansionSetCode = "PLS";
this.subtype.add("Beast");
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// {2}{G}, {tap}, Sacrifice Root Greevil: Destroy all enchantments of the color of your choice.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RootGreevilEffect(), new ManaCostsImpl("{2}{G}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
public RootGreevil(final RootGreevil card) {
super(card);
}
@Override
public RootGreevil copy() {
return new RootGreevil(this);
}
class RootGreevilEffect extends OneShotEffect {
public RootGreevilEffect() {
super(Outcome.DestroyPermanent);
this.staticText = "Destroy all enchantments of the color of your choice";
}
public RootGreevilEffect(final RootGreevilEffect effect) {
super(effect);
}
@Override
public RootGreevilEffect copy() {
return new RootGreevilEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
ChoiceColor choice = new ChoiceColor();
controller.choose(Outcome.DestroyPermanent, choice, game);
if (choice.getColor() != null) {
FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent();
filter.add(new ColorPredicate(choice.getColor()));
for (Permanent enchantment : game.getBattlefield().getAllActivePermanents(filter, game)) {
enchantment.destroy(source.getSourceId(), game, false);
}
}
return true;
}
return false;
}
}
}

View file

@ -1,62 +1,65 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.condition.common; package mage.sets.ravnica;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.MageInt;
import mage.abilities.condition.Condition; import mage.abilities.common.DealtDamageToSourceTriggeredAbility;
import mage.filter.common.FilterCreaturePermanent; import mage.abilities.effects.common.GainLifeEffect;
import mage.game.Game; import mage.cards.CardImpl;
import mage.constants.CardType;
/** import mage.constants.Rarity;
* @author jeff import mage.constants.Zone;
*/
public class NoCreatureOpponentCondition implements Condition { /**
*
private static NoCreatureOpponentCondition fInstance = new NoCreatureOpponentCondition(); * @author Derpthemeus
*/
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); public class DromadPurebred extends CardImpl {
public static Condition getInstance() { public DromadPurebred(UUID ownerId) {
return fInstance; super(ownerId, 15, "Dromad Purebred", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{W}");
} this.expansionSetCode = "RAV";
this.subtype.add("Camel");
@Override this.subtype.add("Beast");
public boolean apply(Game game, Ability source) { this.power = new MageInt(1);
int condition = 0; this.toughness = new MageInt(5);
for (UUID opponent : game.getOpponents(source.getControllerId())) {
if (game.getBattlefield().countAll(filter, opponent, game) == 0) { // Whenever Dromad Purebred is dealt damage, you gain 1 life.
condition++; this.addAbility(new DealtDamageToSourceTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(1), false));
} }
}
if (condition == 0) public DromadPurebred(final DromadPurebred card) {
return false; super(card);
else return true; }
}
} @Override
public DromadPurebred copy() {
return new DromadPurebred(this);
}
}

View file

@ -34,6 +34,7 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.Cards; import mage.cards.Cards;
@ -62,7 +63,7 @@ public class LurkingInformant extends CardImpl {
// <i>({UB} can be paid with either {U} or {B}.)</i> // <i>({UB} can be paid with either {U} or {B}.)</i>
// {2}, {tap}: Look at the top card of target player's library. You may put that card into that player's graveyard. // {2}, {tap}: Look at the top card of target player's library. You may put that card into that player's graveyard.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LurkingInformantEffect(), new GenericManaCost(2)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryTopCardTargetPlayerEffect(1, true), new GenericManaCost(2));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
ability.addTarget(new TargetPlayer()); ability.addTarget(new TargetPlayer());
this.addAbility(ability); this.addAbility(ability);
@ -77,42 +78,3 @@ public class LurkingInformant extends CardImpl {
return new LurkingInformant(this); return new LurkingInformant(this);
} }
} }
class LurkingInformantEffect extends OneShotEffect {
public LurkingInformantEffect() {
super(Outcome.Detriment);
staticText = "Look at the top card of target player's library. You may put that card into his or her graveyard";
}
public LurkingInformantEffect(final LurkingInformantEffect effect) {
super(effect);
}
@Override
public LurkingInformantEffect copy() {
return new LurkingInformantEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(source.getFirstTarget());
if (controller != null && player != null) {
Card card = player.getLibrary().getFromTop(game);
if (card != null) {
Cards cards = new CardsImpl();
cards.add(card);
controller.lookAtCards("Lurking Informant", cards, game);
if (controller.chooseUse(outcome, "Do you wish to put card into the player's graveyard?", source, game)) {
controller.moveCardToGraveyardWithInfo(card, source.getSourceId(), game, Zone.LIBRARY);
} else {
game.informPlayers(controller.getLogName() + " puts the card back on top of the library.");
}
return true;
}
}
return false;
}
}

View file

@ -28,18 +28,10 @@
package mage.sets.starter1999; package mage.sets.starter1999;
import java.util.UUID; import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
/** /**
@ -53,7 +45,7 @@ public class EyeSpy extends CardImpl {
this.expansionSetCode = "S99"; this.expansionSetCode = "S99";
// Look at the top card of target player's library. You may put that card into his or her graveyard. // Look at the top card of target player's library. You may put that card into his or her graveyard.
this.getSpellAbility().addEffect(new EyeSpyEffect()); this.getSpellAbility().addEffect(new LookLibraryTopCardTargetPlayerEffect(1, true));
this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addTarget(new TargetPlayer());
} }
@ -66,42 +58,3 @@ public class EyeSpy extends CardImpl {
return new EyeSpy(this); return new EyeSpy(this);
} }
} }
class EyeSpyEffect extends OneShotEffect {
public EyeSpyEffect() {
super(Outcome.Detriment);
staticText = "Look at the top card of target player's library. You may put that card into his or her graveyard";
}
public EyeSpyEffect(final EyeSpyEffect effect) {
super(effect);
}
@Override
public EyeSpyEffect copy() {
return new EyeSpyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player player = game.getPlayer(source.getFirstTarget());
if (controller != null && player != null) {
Card card = player.getLibrary().getFromTop(game);
if (card != null) {
Cards cards = new CardsImpl();
cards.add(card);
controller.lookAtCards("Eye Spy", cards, game);
if (controller.chooseUse(outcome, "Do you wish to put card into the player's graveyard?", source, game)) {
controller.moveCardToGraveyardWithInfo(card, source.getSourceId(), game, Zone.LIBRARY);
} else {
game.informPlayers(controller.getLogName() + " puts the card back on top of the library.");
}
return true;
}
}
return false;
}
}

View file

@ -33,7 +33,7 @@ import mage.constants.CardType;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.common.NoCreatureOpponentCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility;
@ -58,10 +58,12 @@ public class Kezzerdrix extends CardImpl {
// First strike // First strike
this.addAbility(FirstStrikeAbility.getInstance()); this.addAbility(FirstStrikeAbility.getInstance());
// At the beginning of your upkeep, if your opponents control no creatures, Kezzerdrix deals 4 damage to you. // At the beginning of your upkeep, if your opponents control no creatures, Kezzerdrix deals 4 damage to you.
ConditionalTriggeredAbility ability = new ConditionalTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageControllerEffect(4), TargetController.YOU, false), NoCreatureOpponentCondition.getInstance(), "At the beginning of your upkeep, if your opponents control no creatures, {this} deals 4 damage to you."); this.addAbility(new ConditionalTriggeredAbility(
this.addAbility(ability); new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageControllerEffect(4), TargetController.YOU, false),
new CreatureCountCondition(0, TargetController.OPPONENT),
"At the beginning of your upkeep, if your opponents control no creatures, {this} deals 4 damage to you."));
} }
public Kezzerdrix(final Kezzerdrix card) { public Kezzerdrix(final Kezzerdrix card) {

View file

@ -27,6 +27,7 @@
*/ */
package mage.sets.theros; package mage.sets.theros;
import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -55,21 +56,22 @@ public class ErebossEmissary extends CardImpl {
super(ownerId, 86, "Erebos's Emissary", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{3}{B}"); super(ownerId, 86, "Erebos's Emissary", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{3}{B}");
this.expansionSetCode = "THS"; this.expansionSetCode = "THS";
this.subtype.add("Snake"); this.subtype.add("Snake");
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Bestow {5}{B} // Bestow {5}{B}
this.addAbility(new BestowAbility(this, "{5}{B}")); this.addAbility(new BestowAbility(this, "{5}{B}"));
// Discard a creature card: Erebos's Emissary gets +2/+2 until end of turn. If Erebos's Emissary is an Aura, enchanted creature gets +2/+2 until end of turn instead. // Discard a creature card: Erebos's Emissary gets +2/+2 until end of turn. If Erebos's Emissary is an Aura, enchanted creature gets +2/+2 until end of turn instead.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new BoostEnchantedEffect(2,2, Duration.EndOfTurn), new BoostEnchantedEffect(2, 2, Duration.EndOfTurn),
new BoostSourceEffect(2,2, Duration.EndOfTurn), new BoostSourceEffect(2, 2, Duration.EndOfTurn),
new SourceHasSubtypeCondition("Aura"), new SourceHasSubtypeCondition(Arrays.asList("Aura")),
"{this} gets +2/+2 until end of turn. If Erebos's Emissary is an Aura, enchanted creature gets +2/+2 until end of turn instead"), "{this} gets +2/+2 until end of turn. If Erebos's Emissary is an Aura, enchanted creature gets +2/+2 until end of turn instead"),
new DiscardTargetCost(new TargetCardInHand(new FilterCreatureCard())))); new DiscardTargetCost(new TargetCardInHand(new FilterCreatureCard()))));
// Enchanted creature gets +3/+3 // Enchanted creature gets +3/+3
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3,3, Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield)));
} }
public ErebossEmissary(final ErebossEmissary card) { public ErebossEmissary(final ErebossEmissary card) {

View file

@ -34,12 +34,13 @@ import mage.constants.Rarity;
import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbility;
import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.NoCreatureCondition; import mage.abilities.condition.common.CreatureCountCondition;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.DamageEverythingEffect;
import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -55,10 +56,9 @@ public class Pestilence extends CardImpl {
super(ownerId, 147, "Pestilence", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); super(ownerId, 147, "Pestilence", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}");
this.expansionSetCode = "USG"; this.expansionSetCode = "USG";
// At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pestilence. // At the beginning of the end step, if no creatures are on the battlefield, sacrifice Pestilence.
TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect()); TriggeredAbility triggered = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect());
this.addAbility(new ConditionalTriggeredAbility(triggered, new NoCreatureCondition(), ruleText)); this.addAbility(new ConditionalTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText));
// {B}: Pestilence deals 1 damage to each creature and each player. // {B}: Pestilence deals 1 damage to each creature and each player.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{B}"))); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{B}")));

View file

@ -0,0 +1,90 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.weatherlight;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author Derpthemeus
*/
public class BlossomingWreath extends CardImpl {
public BlossomingWreath(UUID ownerId) {
super(ownerId, 62, "Blossoming Wreath", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}");
this.expansionSetCode = "WTH";
// You gain life equal to the number of creature cards in your graveyard.
this.getSpellAbility().addEffect(new BlossomingWreathEffect());
}
public BlossomingWreath(final BlossomingWreath card) {
super(card);
}
@Override
public BlossomingWreath copy() {
return new BlossomingWreath(this);
}
class BlossomingWreathEffect extends OneShotEffect {
public BlossomingWreathEffect() {
super(Outcome.GainLife);
this.staticText = "You gain life equal to the number of creature cards in your graveyard";
}
public BlossomingWreathEffect(final BlossomingWreathEffect effect) {
super(effect);
}
@Override
public BlossomingWreathEffect copy() {
return new BlossomingWreathEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
controller.gainLife(controller.getGraveyard().count(new FilterCreatureCard(), game), game);
return true;
}
return false;
}
}
}

View file

@ -1,52 +1,65 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.condition.common; package mage.sets.weatherlight;
import mage.abilities.Ability; import java.util.UUID;
import mage.abilities.condition.Condition; import mage.MageInt;
import mage.filter.common.FilterCreaturePermanent; import mage.abilities.common.DiesTriggeredAbility;
import mage.game.Game; import mage.abilities.effects.common.SacrificeAllEffect;
import mage.cards.CardImpl;
/** import mage.constants.CardType;
* @author nantuko import mage.constants.Rarity;
*/ import mage.filter.common.FilterControlledLandPermanent;
public class NoCreatureCondition implements Condition {
/**
private static final NoCreatureCondition fInstance = new NoCreatureCondition(); *
* @author Derpthemeus
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); */
public class HurloonShaman extends CardImpl {
public static Condition getInstance() {
return fInstance; public HurloonShaman(UUID ownerId) {
} super(ownerId, 108, "Hurloon Shaman", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{R}");
this.expansionSetCode = "WTH";
@Override this.subtype.add("Minotaur");
public boolean apply(Game game, Ability source) { this.subtype.add("Shaman");
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0; this.power = new MageInt(2);
} this.toughness = new MageInt(3);
}
// When Hurloon Shaman dies, each player sacrifices a land.
this.addAbility(new DiesTriggeredAbility(new SacrificeAllEffect(new FilterControlledLandPermanent("land"))));
}
public HurloonShaman(final HurloonShaman card) {
super(card);
}
@Override
public HurloonShaman copy() {
return new HurloonShaman(this);
}
}

View file

@ -1,52 +1,64 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.condition.common; package mage.sets.weatherlight;
import mage.abilities.Ability; import java.util.UUID;
import mage.abilities.condition.Condition; import mage.MageInt;
import mage.filter.common.FilterCreaturePermanent; import mage.abilities.common.SpellCastOpponentTriggeredAbility;
import mage.game.Game; import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.CardImpl;
/** import mage.constants.CardType;
* @author noxx import mage.constants.Rarity;
*/ import mage.filter.common.FilterCreatureSpell;
public class NoControlledCreatureCondition implements Condition {
/**
private static NoControlledCreatureCondition fInstance = new NoControlledCreatureCondition(); *
* @author Derpthemeus
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); */
public class StrawGolem extends CardImpl {
public static Condition getInstance() {
return fInstance; public StrawGolem(UUID ownerId) {
} super(ownerId, 158, "Straw Golem", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}");
this.expansionSetCode = "WTH";
@Override this.subtype.add("Golem");
public boolean apply(Game game, Ability source) { this.power = new MageInt(2);
return game.getBattlefield().countAll(filter, source.getControllerId(), game) == 0; this.toughness = new MageInt(3);
}
} // When an opponent casts a creature spell, sacrifice Straw Golem.
this.addAbility(new SpellCastOpponentTriggeredAbility(new SacrificeSourceEffect(), new FilterCreatureSpell("a creature spell"), false));
}
public StrawGolem(final StrawGolem card) {
super(card);
}
@Override
public StrawGolem copy() {
return new StrawGolem(this);
}
}

View file

@ -7,6 +7,7 @@ package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -16,9 +17,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
*/ */
public class ProwlTest extends CardTestPlayerBase { public class ProwlTest extends CardTestPlayerBase {
@Ignore // have not figured out how to have the test API cast a card using Prowl yet
@Test @Test
public void testBasicProwlCasting() { public void testBasicProwlCasting() {
// Auntie's Snitch {2}{B} Creature Goblin Rogue (3/1) // Auntie's Snitch {2}{B} Creature Goblin Rogue (3/1)
// Auntie's Snitch can't block. // Auntie's Snitch can't block.
// Prowl {1}{B} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Goblin or Rogue.) // Prowl {1}{B} (You may cast this for its prowl cost if you dealt combat damage to a player this turn with a Goblin or Rogue.)
@ -46,6 +47,7 @@ public class ProwlTest extends CardTestPlayerBase {
* Reported bug: Prowl is not taking into consideration other cost reducing effects. For instance Goblin Warchief * Reported bug: Prowl is not taking into consideration other cost reducing effects. For instance Goblin Warchief
* does not reduce the Prowl cost of other Goblin cards with Prowl ability. * does not reduce the Prowl cost of other Goblin cards with Prowl ability.
*/ */
@Ignore // have not figured out how to have the test API cast a card using Prowl yet
@Test @Test
public void testProwlWithCostDiscount() { public void testProwlWithCostDiscount() {

View file

@ -0,0 +1,56 @@
package org.mage.test.cards.single;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author cg5
*/
public class GratuitousViolenceTest extends CardTestPlayerBase {
@Test
public void testDoublesDamageFromCreatures() {
// Enchantment: If a creature you control would deal damage to a creature
// or player, it deals double that damage to that creature or player instead.
addCard(Zone.BATTLEFIELD, playerA, "Gratuitous Violence");
addCard(Zone.BATTLEFIELD, playerA, "Elvish Visionary"); // 1/1
attack(1, playerA, "Elvish Visionary");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 18);
}
@Test
public void testIgnoresNonCreatures() {
// Legendary Enchantment - Shrine: At the beginning of your upkeep, Honden of Infinite
// Rage deals damage to target creature or player equal to the number of Shrines you control.
addCard(Zone.BATTLEFIELD, playerA, "Honden of Infinite Rage");
addCard(Zone.BATTLEFIELD, playerA, "Gratuitous Violence");
addTarget(playerA, playerB);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
// Honden should deal 1 damage at upkeep (since playerA only
// has one Shrine). GV should not double this.
assertLife(playerB, 19);
}
@Test
public void testIgnoresInstants() {
addCard(Zone.BATTLEFIELD, playerA, "Gratuitous Violence");
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.HAND, playerA, "Lightning Bolt");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerB, 17);
}
}

View file

@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.common;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
* @author Styxo
*/
public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
private FilterCreaturePermanent filter;
private int minAttackers;
public AttacksWithCreaturesTriggeredAbility(Effect effect, int minAttackers) {
this(effect, minAttackers, new FilterCreaturePermanent("creatures"));
}
public AttacksWithCreaturesTriggeredAbility(Effect effect, int minAttackers, FilterCreaturePermanent filter) {
super(Zone.BATTLEFIELD, effect);
this.filter = filter;
this.minAttackers = minAttackers;
}
public AttacksWithCreaturesTriggeredAbility(final AttacksWithCreaturesTriggeredAbility ability) {
super(ability);
this.filter = ability.filter;
this.minAttackers = ability.minAttackers;
}
@Override
public AttacksWithCreaturesTriggeredAbility copy() {
return new AttacksWithCreaturesTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
int attackerCount = 0;
for (UUID attacker : game.getCombat().getAttackers()) {
if (filter.match(game.getPermanent(attacker), game)) {
attackerCount++;
}
}
return attackerCount >= minAttackers && game.getCombat().getAttackerId().equals(getControllerId());
}
@Override
public String getRule() {
StringBuilder sb = new StringBuilder("Whenever you attack with " + minAttackers + " or more ");
sb.append(filter.getMessage());
sb.append(", ");
sb.append(super.getRule());
return sb.toString();
}
}

View file

@ -0,0 +1,82 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.condition.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.constants.TargetController;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
/**
*
* @author Styxo
*/
public class CreatureCountCondition implements Condition {
private FilterCreaturePermanent filter;
private int creatureCount;
private TargetController targetController;
public CreatureCountCondition(FilterCreaturePermanent filter, int creatureCount, TargetController targetController) {
this.filter = filter;
this.creatureCount = creatureCount;
this.targetController = targetController;
}
public CreatureCountCondition(int creatureCount, TargetController targetController) {
this.filter = new FilterCreaturePermanent();
this.creatureCount = creatureCount;
this.targetController = targetController;
}
@Override
public boolean apply(Game game, Ability source) {
switch (targetController) {
case YOU:
return game.getBattlefield().countAll(filter, source.getControllerId(), game) == creatureCount;
case OPPONENT:
for (UUID opponent : game.getOpponents(source.getControllerId())) {
if (game.getBattlefield().countAll(filter, opponent, game) != creatureCount) {
return false;
}
}
return true;
case ANY:
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == creatureCount;
default:
throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString());
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
switch (targetController) {
case YOU:
sb.append("you");
break;
case OPPONENT:
sb.append("your opponents");
break;
case ANY:
sb.append("if ");
sb.append(creatureCount);
sb.append(" ");
sb.append(filter.getMessage());
sb.append(" are on the battlefield");
return sb.toString();
}
sb.append(" control exactly ");
sb.append(creatureCount);
sb.append(" ");
sb.append(filter.getMessage());
return sb.toString();
}
}

View file

@ -1,5 +1,6 @@
package mage.abilities.condition.common; package mage.abilities.condition.common;
import java.util.List;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.game.Game; import mage.game.Game;
@ -11,17 +12,21 @@ import mage.game.permanent.Permanent;
*/ */
public class SourceHasSubtypeCondition implements Condition { public class SourceHasSubtypeCondition implements Condition {
private final String subtype; private final List<String> subtypes;
public SourceHasSubtypeCondition(String subtype) { public SourceHasSubtypeCondition(List<String> subtypes) {
this.subtype = subtype; this.subtypes = subtypes;
} }
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) { if (permanent != null) {
return permanent.hasSubtype(subtype, game); for (String subtype : subtypes) {
if (permanent.hasSubtype(subtype, game)) {
return true;
}
}
} }
return false; return false;
} }

View file

@ -30,9 +30,11 @@ package mage.abilities.effects.common;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil; import mage.util.CardUtil;
@ -44,10 +46,19 @@ import mage.util.CardUtil;
public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect { public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
protected int amount; protected int amount;
protected boolean putToGraveyard;
public LookLibraryTopCardTargetPlayerEffect(int amount) { public LookLibraryTopCardTargetPlayerEffect(int amount) {
super(Outcome.Benefit); super(Outcome.Benefit);
this.amount = amount; this.amount = amount;
this.putToGraveyard = false;
setText();
}
public LookLibraryTopCardTargetPlayerEffect(int amount, boolean putToGraveyard) {
super(Outcome.Benefit);
this.amount = amount;
this.putToGraveyard = putToGraveyard;
setText(); setText();
} }
@ -58,6 +69,7 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
public LookLibraryTopCardTargetPlayerEffect(final LookLibraryTopCardTargetPlayerEffect effect) { public LookLibraryTopCardTargetPlayerEffect(final LookLibraryTopCardTargetPlayerEffect effect) {
super(effect); super(effect);
amount = effect.amount; amount = effect.amount;
putToGraveyard = effect.putToGraveyard;
} }
@Override @Override
@ -74,21 +86,38 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect {
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
cards.addAll(targetPlayer.getLibrary().getTopCards(game, amount)); cards.addAll(targetPlayer.getLibrary().getTopCards(game, amount));
player.lookAtCards(sourceObject.getName(), cards, game); player.lookAtCards(sourceObject.getName(), cards, game);
if (putToGraveyard) {
for (Card card : cards.getCards(game)) {
if (player.chooseUse(outcome, "Do you wish to put card into the player's graveyard?", source, game)) {
player.moveCardToGraveyardWithInfo(card, source.getSourceId(), game, Zone.LIBRARY);
} else {
game.informPlayers(player.getLogName() + " puts the card back on top of the library.");
}
}
}
return true; return true;
} }
return false; return false;
} }
private void setText() { private void setText() {
StringBuilder sb = new StringBuilder("look at the top "); StringBuilder sb = new StringBuilder("look at the top ");
if (amount > 1) { if (amount > 1) {
sb.append(CardUtil.numberToText(amount)); sb.append(CardUtil.numberToText(amount));
sb.append(" cards "); sb.append(" cards ");
} } else {
else {
sb.append(" card "); sb.append(" card ");
} }
sb.append("of target player's library"); sb.append("of target player's library");
if (putToGraveyard) {
sb.append(". You may put ");
if (amount > 1) {
sb.append("those cards");
} else {
sb.append("that card");
}
sb.append(" into that player's graveyard");
}
this.staticText = sb.toString(); this.staticText = sb.toString();
} }
} }

View file

@ -0,0 +1,60 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author Styxo
*/
public class ShuffleIntoLibraryTargetEffect extends OneShotEffect {
public ShuffleIntoLibraryTargetEffect() {
super(Outcome.Detriment);
}
public ShuffleIntoLibraryTargetEffect(String effectText) {
super(Outcome.Detriment);
this.staticText = effectText;
}
public ShuffleIntoLibraryTargetEffect(final ShuffleIntoLibraryTargetEffect effect) {
super(effect);
}
@Override
public ShuffleIntoLibraryTargetEffect copy() {
return new ShuffleIntoLibraryTargetEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
if (permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true)) {
game.getPlayer(permanent.getOwnerId()).shuffleLibrary(source, game);
return true;
}
}
return false;
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
} else {
return "choose target " + mode.getTargets().get(0).getTargetName() + ". Its owner shuffles it into his or her library";
}
}
}

View file

@ -0,0 +1,59 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common.continuous;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
/**
*
* @author Styxo
*/
public class ActivateAbilitiesAnyTimeYouCouldCastInstantEffect extends AsThoughEffectImpl {
private Class activatedAbility;
public ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(Class activatedAbility, String activatedAbilityName) {
super(AsThoughEffectType.ACTIVATE_AS_INSTANT, Duration.EndOfGame, Outcome.Benefit);
this.activatedAbility = activatedAbility;
staticText = "You may activate " + activatedAbilityName + " any time you could cast an instant";
}
public ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(final ActivateAbilitiesAnyTimeYouCouldCastInstantEffect effect) {
super(effect);
this.activatedAbility = effect.activatedAbility;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public ActivateAbilitiesAnyTimeYouCouldCastInstantEffect copy() {
return new ActivateAbilitiesAnyTimeYouCouldCastInstantEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game) {
if (affectedAbility.getControllerId().equals(source.getControllerId())
&& activatedAbility.isInstance(affectedAbility)) {
return true;
}
return false;
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return false; // Not used
}
}

View file

@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.effects.common.cost;
import mage.abilities.Ability;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.util.CardUtil;
/**
*
* @author Styxo
*/
public class AbilitiesCostReductionControllerEffect extends CostModificationEffectImpl {
private Class activatedAbility;
public AbilitiesCostReductionControllerEffect(Class activatedAbility, String activatedAbilityName) {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.activatedAbility = activatedAbility;
staticText = activatedAbilityName + " costs you pay cost {1} less";
}
public AbilitiesCostReductionControllerEffect(AbilitiesCostReductionControllerEffect effect) {
super(effect);
this.activatedAbility = effect.activatedAbility;
}
@java.lang.Override
public AbilitiesCostReductionControllerEffect copy() {
return new AbilitiesCostReductionControllerEffect(this);
}
@java.lang.Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.reduceCost(abilityToModify, 1);
return true;
}
@java.lang.Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify.getControllerId().equals(source.getControllerId())
&& activatedAbility.isInstance(abilityToModify);
}
}

View file

@ -65,6 +65,8 @@ public interface Card extends MageObject {
String getExpansionSetCode(); String getExpansionSetCode();
String getTokenSetCode(); String getTokenSetCode();
String getTokenDescriptor();
void checkForCountersToAdd(Permanent permanent, Game game); void checkForCountersToAdd(Permanent permanent, Game game);

View file

@ -74,6 +74,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
protected String cardNumber; protected String cardNumber;
public String expansionSetCode; public String expansionSetCode;
protected String tokenSetCode; protected String tokenSetCode;
protected String tokenDescriptor;
protected Rarity rarity; protected Rarity rarity;
protected boolean canTransform; protected boolean canTransform;
protected Card secondSideCard; protected Card secondSideCard;
@ -316,6 +317,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
public String getTokenSetCode() { public String getTokenSetCode() {
return tokenSetCode; return tokenSetCode;
} }
@Override
public String getTokenDescriptor() {
return tokenDescriptor;
}
@Override @Override
public List<Mana> getMana() { public List<Mana> getMana() {

View file

@ -86,6 +86,7 @@ public class PermanentToken extends PermanentImpl {
this.toughness.modifyBaseValue(token.getToughness().getBaseValueModified()); this.toughness.modifyBaseValue(token.getToughness().getBaseValueModified());
this.supertype = token.getSupertype(); this.supertype = token.getSupertype();
this.subtype = token.getSubtype(game); this.subtype = token.getSubtype(game);
this.tokenDescriptor = token.getTokenDescriptor();
} }
@Override @Override

View file

@ -55,6 +55,7 @@ public class Token extends MageObjectImpl {
private int tokenType; private int tokenType;
private String originalCardNumber; private String originalCardNumber;
private String originalExpansionSetCode; private String originalExpansionSetCode;
private String tokenDescriptor;
private boolean expansionSetCodeChecked; private boolean expansionSetCodeChecked;
private Card copySourceCard; // the card the Token is a copy from private Card copySourceCard; // the card the Token is a copy from
@ -113,6 +114,26 @@ public class Token extends MageObjectImpl {
this.copySourceCard = token.copySourceCard; // will never be changed this.copySourceCard = token.copySourceCard; // will never be changed
this.availableImageSetCodes = token.availableImageSetCodes; this.availableImageSetCodes = token.availableImageSetCodes;
} }
private void setTokenDescriptor() {
this.tokenDescriptor = tokenDescriptor();
}
public String getTokenDescriptor() {
this.tokenDescriptor = tokenDescriptor();
return tokenDescriptor;
}
private String tokenDescriptor() {
String name = this.name.replaceAll("[^a-zA-Z0-9]", "");
String color = this.color.toString().replaceAll("[^a-zA-Z0-9]", "");
String subtype = this.subtype.toString().replaceAll("[^a-zA-Z0-9]", "");
String cardType = this.cardType.toString().replaceAll("[^a-zA-Z0-9]", "");
String originalset = this.getOriginalExpansionSetCode();
String descriptor = name + "." + color + "." + subtype + "." + cardType + "." + this.power + "." + this.toughness ;
descriptor = descriptor.toUpperCase();
return descriptor;
}
public String getDescription() { public String getDescription() {
return description; return description;
@ -241,13 +262,14 @@ public class Token extends MageObjectImpl {
public void setOriginalCardNumber(String originalCardNumber) { public void setOriginalCardNumber(String originalCardNumber) {
this.originalCardNumber = originalCardNumber; this.originalCardNumber = originalCardNumber;
} }
public String getOriginalExpansionSetCode() { public String getOriginalExpansionSetCode() {
return originalExpansionSetCode; return originalExpansionSetCode;
} }
public void setOriginalExpansionSetCode(String originalExpansionSetCode) { public void setOriginalExpansionSetCode(String originalExpansionSetCode) {
this.originalExpansionSetCode = originalExpansionSetCode; this.originalExpansionSetCode = originalExpansionSetCode;
setTokenDescriptor();
} }
public Card getCopySourceCard() { public Card getCopySourceCard() {
@ -264,15 +286,20 @@ public class Token extends MageObjectImpl {
if (availableImageSetCodes.size() > 0) { if (availableImageSetCodes.size() > 0) {
if (availableImageSetCodes.contains(code)) { if (availableImageSetCodes.contains(code)) {
setOriginalExpansionSetCode(code); setOriginalExpansionSetCode(code);
} else // we should not set random set if appropriate set is already used } else {
if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty() // we should not set random set if appropriate set is already used
|| !availableImageSetCodes.contains(getOriginalExpansionSetCode())) { if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty()
setOriginalExpansionSetCode(availableImageSetCodes.get(new Random().nextInt(availableImageSetCodes.size()))); || !availableImageSetCodes.contains(getOriginalExpansionSetCode())) {
setOriginalExpansionSetCode(availableImageSetCodes.get(new Random().nextInt(availableImageSetCodes.size())));
}
}
} else {
if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty()) {
setOriginalExpansionSetCode(code);
} }
} else if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty()) {
setOriginalExpansionSetCode(code);
} }
} setTokenDescriptor();
}
public boolean updateExpansionSetCode(String setCode) { public boolean updateExpansionSetCode(String setCode) {
if (setCode == null || setCode.isEmpty()) { if (setCode == null || setCode.isEmpty()) {

View file

@ -572,6 +572,11 @@ public class Spell extends StackObjImpl implements Card {
public String getTokenSetCode() { public String getTokenSetCode() {
return card.getTokenSetCode(); return card.getTokenSetCode();
} }
@Override
public String getTokenDescriptor() {
return card.getTokenDescriptor();
}
@Override @Override
public void setFaceDown(boolean value, Game game) { public void setFaceDown(boolean value, Game game) {

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.target.common; package mage.target.common;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
@ -44,6 +43,10 @@ public class TargetControlledCreaturePermanent extends TargetControlledPermanent
this(numTargets, numTargets, new FilterControlledCreaturePermanent(), false); this(numTargets, numTargets, new FilterControlledCreaturePermanent(), false);
} }
public TargetControlledCreaturePermanent(int minNumTargets, int maxNumTargets) {
this(minNumTargets, maxNumTargets, new FilterControlledCreaturePermanent(), false);
}
public TargetControlledCreaturePermanent(FilterControlledCreaturePermanent filter) { public TargetControlledCreaturePermanent(FilterControlledCreaturePermanent filter) {
super(1, 1, filter, false); super(1, 1, filter, false);
} }