diff --git a/.gitignore b/.gitignore index 227cae92d1..6f5e1ab0f1 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ hs_err*.log *.txt Mage.Client/serverlist.txt /bin/ +/out/ /target/ client_secrets.json diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/CardDownloadData.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/CardDownloadData.java index 7155869366..49a780eec6 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/CardDownloadData.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/CardDownloadData.java @@ -12,6 +12,7 @@ public class CardDownloadData { private String downloadName; private String set; private String tokenSetCode; + private String tokenDescriptor; private String collectorId; private Integer type; private boolean token; @@ -23,15 +24,15 @@ public class CardDownloadData { private boolean usesVariousArt; private boolean isType2; - public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode) { - this(name, set, collectorId, usesVariousArt, type, tokenSetCode, false); + public CardDownloadData(String name, String set, String collectorId, boolean usesVariousArt, Integer type, String tokenSetCode, String tokenDescriptor) { + 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) { - this(name, set, collectorId, usesVariousArt, type, tokenSetCode, token, false, false); + 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, 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.set = set; this.collectorId = collectorId; @@ -41,6 +42,7 @@ public class CardDownloadData { this.twoFacedCard = twoFacedCard; this.secondSide = secondSide; this.tokenSetCode = tokenSetCode; + this.tokenDescriptor = tokenDescriptor; } public CardDownloadData(final CardDownloadData card) { @@ -117,7 +119,7 @@ public class CardDownloadData { public String getSet() { return set; } - + public void setSet(String set) { this.set = set; } @@ -130,6 +132,13 @@ public class CardDownloadData { this.tokenSetCode = tokenSetCode; } + public String getTokenDescriptor() { + return tokenDescriptor; + } + + public void setTokenDescriptor(String tokenDescriptor) { + this.tokenDescriptor = tokenDescriptor; + } public boolean isToken() { return token; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index fd45594345..339db215fe 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -239,7 +239,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab TFile file; for (CardInfo card : allCards) { 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)); if (!file.exists()) { return true; @@ -285,7 +286,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab && !ignoreUrls.contains(card.getSetCode())) { String cardName = card.getName(); 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()) { url.setDownloadName(createDownloadName(card)); } @@ -299,7 +300,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab if (card.getSecondSideName() == null || card.getSecondSideName().trim().isEmpty()) { 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); allCardsUrls.add(url); } @@ -307,7 +308,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab if (card.getFlipCardName() == null || card.getFlipCardName().trim().isEmpty()) { 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.setFlippedSide(true); url.setType2(isType2); @@ -385,19 +386,19 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } if (params[1].toLowerCase().equals("generate") && params[2].startsWith("TOK:")) { 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); } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM:")) { 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); } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM-:")) { 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); } else if (params[1].toLowerCase().equals("generate") && params[2].startsWith("EMBLEM!:")) { 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); } } else { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java index db0d9958ba..8f53cc2f9f 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java @@ -47,7 +47,7 @@ public class ImageCache { /** * Common pattern for keys. Format: "##" */ - private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)"); + private static final Pattern KEY_PATTERN = Pattern.compile("(.*)#(.*)#(.*)#(.*)#(.*)#(.*)"); static { IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function() { @@ -56,12 +56,12 @@ public class ImageCache { try { boolean usesVariousArt = false; - if (key.endsWith("#usesVariousArt")) { + if (key.matches(".*#usesVariousArt.*")) { usesVariousArt = true; key = key.replace("#usesVariousArt", ""); } boolean thumbnail = false; - if (key.endsWith("#thumb")) { + if (key.matches(".*#thumb.*")) { thumbnail = true; key = key.replace("#thumb", ""); } @@ -76,8 +76,9 @@ public class ImageCache { collectorId = "0"; } 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; if (collectorId.isEmpty() || "0".equals(collectorId)) { @@ -154,7 +155,7 @@ public class ImageCache { } 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); String path = CardImageUtils.generateTokenImagePath(info); if (path == null) { @@ -165,7 +166,7 @@ public class ImageCache { } 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); String path = CardImageUtils.generateTokenImagePath(info); if (path == null) { @@ -238,8 +239,8 @@ public class ImageCache { return name + "#" + card.getExpansionSetCode() + "#" + card.getType() + "#" + card.getCardNumber() + "#" + (card.getTokenSetCode() == null ? "" : card.getTokenSetCode()) + suffix - + (card.getUsesVariousArt() ? "#usesVariousArt" : ""); - + + (card.getUsesVariousArt() ? "#usesVariousArt" : "") + + (card.getTokenDescriptor() != null ? "#" + card.getTokenDescriptor() : "#"); } // /** diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java index 639c0590c9..8e69839c56 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java @@ -42,7 +42,7 @@ public class CardImageUtils { 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; } @@ -50,6 +50,11 @@ public class CardImageUtils { String filename = generateImagePath(card); TFile file = new TFile(filename); + if (!file.exists()) { + filename = generateTokenDescriptorImagePath(card); + } + + file = new TFile(filename); if (!file.exists()) { CardDownloadData updated = new CardDownloadData(card); updated.setName(card.getName() + " 1"); @@ -86,7 +91,7 @@ public class CardImageUtils { // return path; // } // } - return ""; + return generateTokenDescriptorImagePath(card); } public static String updateSet(String cardSet, boolean forUrl) { @@ -102,17 +107,28 @@ public class CardImageUtils { private static String getImageDir(CardDownloadData card, String imagesPath) { if (card.getSet() == null) { - return ""; - } + return ""; + } 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()) { return buildTokenPath(imagesDir, set); } else { 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) { if (PreferencesDialog.isSaveImagesToZip()) { return imagesDir + TFile.separator + "TOK" + ".zip" + TFile.separator + set; @@ -156,7 +172,31 @@ public class CardImageUtils { 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() { Preferences prefs = MageFrame.getPreferences(); Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None")); diff --git a/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java b/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java index dd09951d8d..16599a8379 100644 --- a/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java +++ b/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java @@ -18,15 +18,15 @@ public class TokensMtgImageSourceTest { public void generateTokenUrlTest() throws Exception { 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); - 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); - 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); - 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); } } diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 207cb231f0..7a4f673248 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -159,7 +159,7 @@ public class CardView extends SimpleCardView { * @param storeZone if true the card zone will be set in the zone attribute. */ public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) { - super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null); + 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 // TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2 boolean showFaceUp = true; @@ -291,6 +291,7 @@ public class CardView extends SimpleCardView { } else { // a created token this.expansionSetCode = ((PermanentToken) card).getExpansionSetCode(); + this.tokenDescriptor = ((PermanentToken) card).getTokenDescriptor(); } // // 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) { - super(object.getId(), "", "0", false, "", true); + super(object.getId(), "", "0", false, "", true, ""); this.name = object.getName(); this.displayName = object.getName(); if (object instanceof Permanent) { @@ -376,7 +377,7 @@ public class CardView extends SimpleCardView { } protected CardView() { - super(null, "", "0", false, "", true); + super(null, "", "0", false, "", true, ""); } public CardView(EmblemView emblem) { @@ -393,7 +394,7 @@ public class CardView extends SimpleCardView { } public CardView(boolean empty) { - super(null, "", "0", false, ""); + super(null, "", "0", false, "", ""); if (!empty) { throw new IllegalArgumentException("Not supported."); } @@ -442,7 +443,7 @@ public class CardView extends SimpleCardView { } CardView(Token token) { - super(token.getId(), "", "0", false, ""); + super(token.getId(), "", "0", false, "", ""); this.isToken = true; this.id = token.getId(); this.name = token.getName(); @@ -459,6 +460,7 @@ public class CardView extends SimpleCardView { this.rarity = Rarity.NA; this.type = token.getTokenType(); this.tokenSetCode = token.getOriginalExpansionSetCode(); + this.tokenDescriptor = token.getTokenDescriptor(); } protected final void setTargets(Targets targets) { diff --git a/Mage.Common/src/mage/view/LookedAtView.java b/Mage.Common/src/mage/view/LookedAtView.java index a7485e7120..ac965c6e31 100644 --- a/Mage.Common/src/mage/view/LookedAtView.java +++ b/Mage.Common/src/mage/view/LookedAtView.java @@ -46,7 +46,7 @@ public class LookedAtView implements Serializable { public LookedAtView(String name, Cards cards, Game game) { this.name = name; 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())); } } diff --git a/Mage.Common/src/mage/view/PermanentView.java b/Mage.Common/src/mage/view/PermanentView.java index 9ec311a269..e0b79cabe0 100644 --- a/Mage.Common/src/mage/view/PermanentView.java +++ b/Mage.Common/src/mage/view/PermanentView.java @@ -81,6 +81,7 @@ public class PermanentView extends CardView { original = new CardView(((PermanentToken) permanent).getToken()); original.expansionSetCode = permanent.getExpansionSetCode(); tokenSetCode = original.getTokenSetCode(); + tokenDescriptor = original.getTokenDescriptor(); } else { if (card != null) { // original may not be face down diff --git a/Mage.Common/src/mage/view/SimpleCardView.java b/Mage.Common/src/mage/view/SimpleCardView.java index 2a4c4d5e67..709e45ad83 100644 --- a/Mage.Common/src/mage/view/SimpleCardView.java +++ b/Mage.Common/src/mage/view/SimpleCardView.java @@ -39,16 +39,18 @@ public class SimpleCardView implements Serializable { protected UUID id; protected String expansionSetCode; protected String tokenSetCode; + protected String tokenDescriptor; protected String cardNumber; protected boolean usesVariousArt; protected boolean gameObject; - public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode) { - this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false); + public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, String tokenDescriptor) { + 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.expansionSetCode = expansionSetCode; + this.tokenDescriptor = tokenDescriptor; this.cardNumber = cardNumber; this.usesVariousArt = usesVariousArt; this.tokenSetCode = tokenSetCode; @@ -74,6 +76,10 @@ public class SimpleCardView implements Serializable { public String getTokenSetCode() { return tokenSetCode; } + + public String getTokenDescriptor() { + return tokenDescriptor; + } public boolean isGameObject() { return gameObject; diff --git a/Mage.Common/src/mage/view/SimpleCardsView.java b/Mage.Common/src/mage/view/SimpleCardsView.java index 909d0ee286..990d4b87b1 100644 --- a/Mage.Common/src/mage/view/SimpleCardsView.java +++ b/Mage.Common/src/mage/view/SimpleCardsView.java @@ -44,7 +44,8 @@ public class SimpleCardsView extends LinkedHashMap { public SimpleCardsView(Collection cards, boolean isGameObject) { 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())); } } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DemonicRising.java b/Mage.Sets/src/mage/sets/avacynrestored/DemonicRising.java index 5e6550a2a9..831bfe57a4 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DemonicRising.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DemonicRising.java @@ -31,13 +31,13 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; -import mage.abilities.condition.common.OneControlledCreatureCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.game.permanent.token.DemonToken; - import java.util.UUID; +import mage.abilities.condition.common.CreatureCountCondition; +import mage.constants.TargetController; /** * @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. 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) { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/HomicidalSeclusion.java b/Mage.Sets/src/mage/sets/avacynrestored/HomicidalSeclusion.java index e335e302a9..c4cbc9dea8 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/HomicidalSeclusion.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/HomicidalSeclusion.java @@ -30,7 +30,7 @@ package mage.sets.avacynrestored; import java.util.UUID; import mage.abilities.Ability; 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.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -41,6 +41,7 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; +import mage.constants.TargetController; 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. 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); 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); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/PredatorsGambit.java b/Mage.Sets/src/mage/sets/avacynrestored/PredatorsGambit.java index 6a5a1f54a0..a721475341 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/PredatorsGambit.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/PredatorsGambit.java @@ -30,7 +30,6 @@ package mage.sets.avacynrestored; import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.OneControlledCreatureCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.AttachEffect; @@ -41,8 +40,8 @@ import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; - import java.util.UUID; +import mage.abilities.condition.common.CreatureCountCondition; /** * @author noxx @@ -56,7 +55,6 @@ public class PredatorsGambit extends CardImpl { this.expansionSetCode = "AVR"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); 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. 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)); } diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/AkkiBlizzardHerder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/AkkiBlizzardHerder.java index 4489705454..234738c65c 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/AkkiBlizzardHerder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/AkkiBlizzardHerder.java @@ -43,7 +43,7 @@ import mage.filter.common.FilterControlledPermanent; */ public class AkkiBlizzardHerder extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); + private static final FilterControlledPermanent filter = new FilterControlledLandPermanent("land"); public AkkiBlizzardHerder(UUID ownerId) { super(ownerId, 91, "Akki Blizzard-Herder", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); diff --git a/Mage.Sets/src/mage/sets/bornofthegods/UnravelTheAEther.java b/Mage.Sets/src/mage/sets/bornofthegods/UnravelTheAEther.java index cd44c1e3e2..a46729f424 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/UnravelTheAEther.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/UnravelTheAEther.java @@ -28,19 +28,13 @@ package mage.sets.bornofthegods; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; import mage.cards.CardImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; import mage.target.TargetPermanent; /** @@ -49,11 +43,10 @@ import mage.target.TargetPermanent; */ public class UnravelTheAEther extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment"); static { - filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.ENCHANTMENT))); + filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.ENCHANTMENT))); } public UnravelTheAEther(UUID ownerId) { @@ -61,9 +54,8 @@ public class UnravelTheAEther extends CardImpl { this.expansionSetCode = "BNG"; // Choose target artifact or enchantment. Its owner shuffles it into his or her library. - this.getSpellAbility().addEffect(new UnravelTheAEtherShuffleIntoLibraryEffect()); - Target target = new TargetPermanent(1, 1, filter, false); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(1, 1, filter, true)); } public UnravelTheAEther(final UnravelTheAEther card) { @@ -75,32 +67,3 @@ public class UnravelTheAEther extends CardImpl { 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; - } -} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java b/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java index 3992300e35..5c4905479d 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/RyuseiTheFallingStar.java @@ -52,8 +52,8 @@ public class RyuseiTheFallingStar extends CardImpl { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } - public RyuseiTheFallingStar(UUID ownerID) { - super(ownerID, 185, "Ryusei, the Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); + public RyuseiTheFallingStar(UUID ownerId) { + super(ownerId, 185, "Ryusei, the Falling Star", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); this.expansionSetCode = "CHK"; this.supertype.add("Legendary"); this.subtype.add("Dragon"); diff --git a/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java b/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java index 25f7580d26..42543ac309 100644 --- a/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java +++ b/Mage.Sets/src/mage/sets/commander2014/TeferiTemporalArchmage.java @@ -28,26 +28,21 @@ package mage.sets.commander2014; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.ActivateAbilitiesAnyTimeYouCouldCastInstantEffect; import mage.cards.CardImpl; -import mage.constants.AsThoughEffectType; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.game.Game; import mage.game.command.Emblem; 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." public TeferiTemporalArchmageEmblem() { 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 - } - -} diff --git a/Mage.Sets/src/mage/sets/darksteel/LeoninShikari.java b/Mage.Sets/src/mage/sets/darksteel/LeoninShikari.java index 50117b4d53..6bf3d8bde6 100644 --- a/Mage.Sets/src/mage/sets/darksteel/LeoninShikari.java +++ b/Mage.Sets/src/mage/sets/darksteel/LeoninShikari.java @@ -29,18 +29,13 @@ package mage.sets.darksteel; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.continuous.ActivateAbilitiesAnyTimeYouCouldCastInstantEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; -import mage.constants.AsThoughEffectType; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.Rarity; import mage.constants.Zone; -import mage.game.Game; /** * @@ -57,7 +52,7 @@ public class LeoninShikari extends CardImpl { this.toughness = new MageInt(2); // 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) { @@ -69,35 +64,3 @@ public class LeoninShikari extends CardImpl { 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 - } -} diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeadlyWanderings.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeadlyWanderings.java index 8558668fb4..b4ac3daf25 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeadlyWanderings.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeadlyWanderings.java @@ -30,7 +30,7 @@ package mage.sets.dragonsoftarkir; import java.util.UUID; import mage.abilities.Ability; 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.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -42,6 +42,7 @@ import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Rarity; +import mage.constants.TargetController; import mage.constants.Zone; 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. 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"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); 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); 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); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java b/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java index 30fc48f26c..e650c98bf4 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java +++ b/Mage.Sets/src/mage/sets/fatereforged/JeskaiInfiltrator.java @@ -38,7 +38,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; 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.ManaCostsImpl; import mage.abilities.decorator.ConditionalRestrictionEffect; @@ -53,6 +53,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Rarity; +import mage.constants.TargetController; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -73,7 +74,7 @@ public class JeskaiInfiltrator extends CardImpl { this.toughness = new MageInt(3); // 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"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/sets/invasion/LightningDart.java b/Mage.Sets/src/mage/sets/invasion/LightningDart.java new file mode 100644 index 0000000000..cde67270ea --- /dev/null +++ b/Mage.Sets/src/mage/sets/invasion/LightningDart.java @@ -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; + } + } +} diff --git a/Mage.Sets/src/mage/sets/magic2012/CallToTheGrave.java b/Mage.Sets/src/mage/sets/magic2012/CallToTheGrave.java index ea04b9077f..b3e0be2874 100644 --- a/Mage.Sets/src/mage/sets/magic2012/CallToTheGrave.java +++ b/Mage.Sets/src/mage/sets/magic2012/CallToTheGrave.java @@ -32,7 +32,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; 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.effects.common.SacrificeEffect; 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}"); this.expansionSetCode = "M12"; - // 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); this.addAbility(ability); // 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()); - this.addAbility(new ConditionalTriggeredAbility(triggered, new NoCreatureCondition(), ruleText)); + this.addAbility(new ConditionalTriggeredAbility(triggered, new CreatureCountCondition(0, TargetController.ANY), ruleText)); } public CallToTheGrave(final CallToTheGrave card) { diff --git a/Mage.Sets/src/mage/sets/magic2014/PathOfBravery.java b/Mage.Sets/src/mage/sets/magic2014/PathOfBravery.java index 885c6c81f3..81831acf89 100644 --- a/Mage.Sets/src/mage/sets/magic2014/PathOfBravery.java +++ b/Mage.Sets/src/mage/sets/magic2014/PathOfBravery.java @@ -29,7 +29,7 @@ package mage.sets.magic2014; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -45,8 +45,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; 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}"); 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. 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. - 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 { private int attackers; diff --git a/Mage.Sets/src/mage/sets/magic2015/MilitaryIntelligence.java b/Mage.Sets/src/mage/sets/magic2015/MilitaryIntelligence.java index 4f1840effb..3782326e9f 100644 --- a/Mage.Sets/src/mage/sets/magic2015/MilitaryIntelligence.java +++ b/Mage.Sets/src/mage/sets/magic2015/MilitaryIntelligence.java @@ -28,16 +28,11 @@ package mage.sets.magic2015; import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.constants.CardType; 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}"); this.expansionSetCode = "M15"; - // 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) { @@ -63,34 +57,3 @@ public class MilitaryIntelligence extends CardImpl { 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() ; - } -} diff --git a/Mage/src/main/java/mage/abilities/condition/common/OneControlledCreatureCondition.java b/Mage.Sets/src/mage/sets/mercadianmasques/MoonlitWake.java similarity index 66% rename from Mage/src/main/java/mage/abilities/condition/common/OneControlledCreatureCondition.java rename to Mage.Sets/src/mage/sets/mercadianmasques/MoonlitWake.java index 44e38f97f4..5a43708b4c 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OneControlledCreatureCondition.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/MoonlitWake.java @@ -1,58 +1,59 @@ -/* - * 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.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; - -/** - * @author noxx - */ -public class OneControlledCreatureCondition implements Condition { - - private static final OneControlledCreatureCondition fInstance = new OneControlledCreatureCondition(); - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - public static Condition getInstance() { - return fInstance; - } - - @Override - public boolean apply(Game game, Ability source) { - return game.getBattlefield().countAll(filter, source.getControllerId(), game) == 1; - } - - @Override - public String toString() { - return "you control exactly one creature"; - } - -} +/* + * 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.mercadianmasques; + +import java.util.UUID; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author Derpthemeus + */ +public class MoonlitWake extends CardImpl { + + public MoonlitWake(UUID ownerId) { + super(ownerId, 29, "Moonlit Wake", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + this.expansionSetCode = "MMQ"; + + // Whenever a creature dies, you gain 1 life. + this.addAbility(new DiesCreatureTriggeredAbility(new GainLifeEffect(1), false)); + } + + public MoonlitWake(final MoonlitWake card) { + super(card); + } + + @Override + public MoonlitWake copy() { + return new MoonlitWake(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/ElixirOfVitality.java b/Mage.Sets/src/mage/sets/mirage/ElixirOfVitality.java new file mode 100644 index 0000000000..6ecff2bf7c --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/ElixirOfVitality.java @@ -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); + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/AuriokSteelshaper.java b/Mage.Sets/src/mage/sets/mirrodin/AuriokSteelshaper.java index ae5b61646a..c701cc584b 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/AuriokSteelshaper.java +++ b/Mage.Sets/src/mage/sets/mirrodin/AuriokSteelshaper.java @@ -29,27 +29,25 @@ package mage.sets.mirrodin; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.EquippedSourceCondition; import mage.abilities.decorator.ConditionalContinuousEffect; 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.cards.CardImpl; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.util.CardUtil; /** * * @author Jason E. Wall - + * */ public class AuriokSteelshaper extends CardImpl { + private static final FilterCreaturePermanent soldiersOrKnights = new FilterCreaturePermanent(); static { @@ -68,7 +66,7 @@ public class AuriokSteelshaper extends CardImpl { this.toughness = new MageInt(1); // 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. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( @@ -87,32 +85,3 @@ public class AuriokSteelshaper extends CardImpl { 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); - } -} diff --git a/Mage.Sets/src/mage/sets/mirrodin/SkyhunterCub.java b/Mage.Sets/src/mage/sets/mirrodin/SkyhunterCub.java new file mode 100644 index 0000000000..b14480385d --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirrodin/SkyhunterCub.java @@ -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); + } +} diff --git a/Mage.Sets/src/mage/sets/morningtide/Deglamer.java b/Mage.Sets/src/mage/sets/morningtide/Deglamer.java index 85d4003e87..0cfe884dcc 100644 --- a/Mage.Sets/src/mage/sets/morningtide/Deglamer.java +++ b/Mage.Sets/src/mage/sets/morningtide/Deglamer.java @@ -29,18 +29,12 @@ package mage.sets.morningtide; import java.util.UUID; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ShuffleIntoLibraryTargetEffect; import mage.cards.CardImpl; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; import mage.target.TargetPermanent; /** @@ -49,21 +43,18 @@ import mage.target.TargetPermanent; */ public class Deglamer extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent("artifact or enchantment"); static { - filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.ENCHANTMENT))); + filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.ENCHANTMENT))); } public Deglamer(UUID ownerId) { super(ownerId, 118, "Deglamer", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{1}{G}"); this.expansionSetCode = "MOR"; - // Choose target artifact or enchantment. Its owner shuffles it into his or her library. - this.getSpellAbility().addEffect(new DeglamerShuffleIntoLibraryEffect()); - Target target = new TargetPermanent(1,1,filter,true); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addEffect(new ShuffleIntoLibraryTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(1, 1, filter, true)); } public Deglamer(final Deglamer card) { @@ -74,33 +65,4 @@ public class Deglamer extends CardImpl { public Deglamer copy() { 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; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/onslaught/AnimalMagnetism.java b/Mage.Sets/src/mage/sets/onslaught/AnimalMagnetism.java index 4716ca3275..8cbe76565a 100644 --- a/Mage.Sets/src/mage/sets/onslaught/AnimalMagnetism.java +++ b/Mage.Sets/src/mage/sets/onslaught/AnimalMagnetism.java @@ -53,8 +53,8 @@ import mage.target.common.TargetOpponent; */ public class AnimalMagnetism extends CardImpl { - public AnimalMagnetism(UUID ownerID) { - super(ownerID, 245, "Animal Magnetism", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{G}"); + public AnimalMagnetism(UUID ownerId) { + super(ownerId, 245, "Animal Magnetism", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{4}{G}"); 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. diff --git a/Mage.Sets/src/mage/sets/onslaught/GrandMelee.java b/Mage.Sets/src/mage/sets/onslaught/GrandMelee.java index 4af0c6fedc..c53189a57d 100644 --- a/Mage.Sets/src/mage/sets/onslaught/GrandMelee.java +++ b/Mage.Sets/src/mage/sets/onslaught/GrandMelee.java @@ -45,8 +45,8 @@ import mage.watchers.common.AttackedThisTurnWatcher; */ public class GrandMelee extends CardImpl { - public GrandMelee(UUID ownerID) { - super(ownerID, 211, "Grand Melee", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + public GrandMelee(UUID ownerId) { + super(ownerId, 211, "Grand Melee", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); this.expansionSetCode = "ONS"; // All creatures attack each turn if able. diff --git a/Mage.Sets/src/mage/sets/onslaught/GratuitousViolence.java b/Mage.Sets/src/mage/sets/onslaught/GratuitousViolence.java index 7bd1e97fb8..908e5c001f 100644 --- a/Mage.Sets/src/mage/sets/onslaught/GratuitousViolence.java +++ b/Mage.Sets/src/mage/sets/onslaught/GratuitousViolence.java @@ -95,7 +95,9 @@ class GratuitousViolenceReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { 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 diff --git a/Mage.Sets/src/mage/sets/onslaught/NovaCleric.java b/Mage.Sets/src/mage/sets/onslaught/NovaCleric.java new file mode 100644 index 0000000000..6fde0c6c94 --- /dev/null +++ b/Mage.Sets/src/mage/sets/onslaught/NovaCleric.java @@ -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); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/Pyrohemia.java b/Mage.Sets/src/mage/sets/planarchaos/Pyrohemia.java index 1c79bd7b92..b7fb9bf3d3 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Pyrohemia.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Pyrohemia.java @@ -31,7 +31,7 @@ import java.util.UUID; import mage.abilities.TriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility; 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.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DamageEverythingEffect; @@ -39,6 +39,7 @@ import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.TargetController; import mage.constants.Zone; import mage.game.events.GameEvent; @@ -47,7 +48,7 @@ import mage.game.events.GameEvent; * @author fireshoes */ 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."; 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. 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. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{R}"))); } diff --git a/Mage.Sets/src/mage/sets/planarchaos/WildPair.java b/Mage.Sets/src/mage/sets/planarchaos/WildPair.java index 8d4ce274ec..8db3fc523c 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/WildPair.java +++ b/Mage.Sets/src/mage/sets/planarchaos/WildPair.java @@ -58,8 +58,8 @@ import mage.watchers.common.CastFromHandWatcher; */ public class WildPair extends CardImpl { - public WildPair(UUID ownerID) { - super(ownerID, 144, "Wild Pair", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); + public WildPair(UUID ownerId) { + super(ownerId, 144, "Wild Pair", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); 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. diff --git a/Mage.Sets/src/mage/sets/planeshift/RootGreevil.java b/Mage.Sets/src/mage/sets/planeshift/RootGreevil.java new file mode 100644 index 0000000000..cb477a6f04 --- /dev/null +++ b/Mage.Sets/src/mage/sets/planeshift/RootGreevil.java @@ -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; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/NoCreatureOpponentCondition.java b/Mage.Sets/src/mage/sets/ravnica/DromadPurebred.java similarity index 60% rename from Mage/src/main/java/mage/abilities/condition/common/NoCreatureOpponentCondition.java rename to Mage.Sets/src/mage/sets/ravnica/DromadPurebred.java index f658c68400..410f3d1b5b 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/NoCreatureOpponentCondition.java +++ b/Mage.Sets/src/mage/sets/ravnica/DromadPurebred.java @@ -1,62 +1,65 @@ -/* - * 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.abilities.condition.common; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; - -/** - * @author jeff - */ -public class NoCreatureOpponentCondition implements Condition { - - private static NoCreatureOpponentCondition fInstance = new NoCreatureOpponentCondition(); - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - public static Condition getInstance() { - return fInstance; - } - - @Override - public boolean apply(Game game, Ability source) { - int condition = 0; - for (UUID opponent : game.getOpponents(source.getControllerId())) { - if (game.getBattlefield().countAll(filter, opponent, game) == 0) { - condition++; - } - } - if (condition == 0) - return false; - else return true; - } -} - +/* + * 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.ravnica; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +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 DromadPurebred extends CardImpl { + + public DromadPurebred(UUID ownerId) { + super(ownerId, 15, "Dromad Purebred", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.expansionSetCode = "RAV"; + this.subtype.add("Camel"); + this.subtype.add("Beast"); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // Whenever Dromad Purebred is dealt damage, you gain 1 life. + this.addAbility(new DealtDamageToSourceTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(1), false)); + } + + public DromadPurebred(final DromadPurebred card) { + super(card); + } + + @Override + public DromadPurebred copy() { + return new DromadPurebred(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ravnica/LurkingInformant.java b/Mage.Sets/src/mage/sets/ravnica/LurkingInformant.java index 6185665046..da7575d9e4 100644 --- a/Mage.Sets/src/mage/sets/ravnica/LurkingInformant.java +++ b/Mage.Sets/src/mage/sets/ravnica/LurkingInformant.java @@ -34,6 +34,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; @@ -62,7 +63,7 @@ public class LurkingInformant extends CardImpl { // ({UB} can be paid with either {U} or {B}.) // {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.addTarget(new TargetPlayer()); this.addAbility(ability); @@ -77,42 +78,3 @@ public class LurkingInformant extends CardImpl { 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; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/starter1999/EyeSpy.java b/Mage.Sets/src/mage/sets/starter1999/EyeSpy.java index 89a6a96863..8f0b002b05 100644 --- a/Mage.Sets/src/mage/sets/starter1999/EyeSpy.java +++ b/Mage.Sets/src/mage/sets/starter1999/EyeSpy.java @@ -28,18 +28,10 @@ package mage.sets.starter1999; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect; import mage.cards.CardImpl; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; /** @@ -53,7 +45,7 @@ public class EyeSpy extends CardImpl { this.expansionSetCode = "S99"; // 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()); } @@ -66,42 +58,3 @@ public class EyeSpy extends CardImpl { 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; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/tempest/Kezzerdrix.java b/Mage.Sets/src/mage/sets/tempest/Kezzerdrix.java index e03c0b94e3..29aa8d9759 100644 --- a/Mage.Sets/src/mage/sets/tempest/Kezzerdrix.java +++ b/Mage.Sets/src/mage/sets/tempest/Kezzerdrix.java @@ -33,7 +33,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.MageInt; 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.effects.common.DamageControllerEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -58,10 +58,12 @@ public class Kezzerdrix extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - + // 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(ability); + this.addAbility(new ConditionalTriggeredAbility( + 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) { diff --git a/Mage.Sets/src/mage/sets/theros/ErebossEmissary.java b/Mage.Sets/src/mage/sets/theros/ErebossEmissary.java index 914d90d249..3fe02cd87a 100644 --- a/Mage.Sets/src/mage/sets/theros/ErebossEmissary.java +++ b/Mage.Sets/src/mage/sets/theros/ErebossEmissary.java @@ -27,6 +27,7 @@ */ package mage.sets.theros; +import java.util.Arrays; import java.util.UUID; import mage.MageInt; 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}"); this.expansionSetCode = "THS"; this.subtype.add("Snake"); - this.power = new MageInt(3); this.toughness = new MageInt(3); // Bestow {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. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostEnchantedEffect(2,2, Duration.EndOfTurn), - new BoostSourceEffect(2,2, Duration.EndOfTurn), - new SourceHasSubtypeCondition("Aura"), + new BoostEnchantedEffect(2, 2, Duration.EndOfTurn), + new BoostSourceEffect(2, 2, Duration.EndOfTurn), + 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"), new DiscardTargetCost(new TargetCardInHand(new FilterCreatureCard())))); + // 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) { diff --git a/Mage.Sets/src/mage/sets/urzassaga/Pestilence.java b/Mage.Sets/src/mage/sets/urzassaga/Pestilence.java index 375939ea64..ddda1f21cb 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Pestilence.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Pestilence.java @@ -34,12 +34,13 @@ import mage.constants.Rarity; import mage.abilities.TriggeredAbility; import mage.abilities.common.OnEventTriggeredAbility; 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.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.DamageEverythingEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; +import mage.constants.TargetController; import mage.constants.Zone; 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}"); this.expansionSetCode = "USG"; - // 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()); - 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. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageEverythingEffect(1), new ManaCostsImpl("{B}"))); diff --git a/Mage.Sets/src/mage/sets/weatherlight/BlossomingWreath.java b/Mage.Sets/src/mage/sets/weatherlight/BlossomingWreath.java new file mode 100644 index 0000000000..5ee599534a --- /dev/null +++ b/Mage.Sets/src/mage/sets/weatherlight/BlossomingWreath.java @@ -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; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/NoCreatureCondition.java b/Mage.Sets/src/mage/sets/weatherlight/HurloonShaman.java similarity index 59% rename from Mage/src/main/java/mage/abilities/condition/common/NoCreatureCondition.java rename to Mage.Sets/src/mage/sets/weatherlight/HurloonShaman.java index 9bfdc3b92a..6e9d72ec42 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/NoCreatureCondition.java +++ b/Mage.Sets/src/mage/sets/weatherlight/HurloonShaman.java @@ -1,52 +1,65 @@ -/* - * 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.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; - -/** - * @author nantuko - */ -public class NoCreatureCondition implements Condition { - - private static final NoCreatureCondition fInstance = new NoCreatureCondition(); - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - public static Condition getInstance() { - return fInstance; - } - - @Override - public boolean apply(Game game, Ability source) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0; - } -} +/* + * 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.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.SacrificeAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledLandPermanent; + +/** + * + * @author Derpthemeus + */ +public class HurloonShaman extends CardImpl { + + public HurloonShaman(UUID ownerId) { + super(ownerId, 108, "Hurloon Shaman", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + this.expansionSetCode = "WTH"; + this.subtype.add("Minotaur"); + this.subtype.add("Shaman"); + 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); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/NoControlledCreatureCondition.java b/Mage.Sets/src/mage/sets/weatherlight/StrawGolem.java similarity index 59% rename from Mage/src/main/java/mage/abilities/condition/common/NoControlledCreatureCondition.java rename to Mage.Sets/src/mage/sets/weatherlight/StrawGolem.java index d41a8682ae..8c2216a62e 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/NoControlledCreatureCondition.java +++ b/Mage.Sets/src/mage/sets/weatherlight/StrawGolem.java @@ -1,52 +1,64 @@ -/* - * 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.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; - -/** - * @author noxx - */ -public class NoControlledCreatureCondition implements Condition { - - private static NoControlledCreatureCondition fInstance = new NoControlledCreatureCondition(); - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - public static Condition getInstance() { - return fInstance; - } - - @Override - public boolean apply(Game game, Ability source) { - return game.getBattlefield().countAll(filter, source.getControllerId(), game) == 0; - } -} +/* + * 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.MageInt; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureSpell; + +/** + * + * @author Derpthemeus + */ +public class StrawGolem extends CardImpl { + + public StrawGolem(UUID ownerId) { + super(ownerId, 158, "Straw Golem", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + this.expansionSetCode = "WTH"; + this.subtype.add("Golem"); + this.power = new MageInt(2); + 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); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ProwlTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ProwlTest.java index 7dd95c4e91..894073777c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ProwlTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ProwlTest.java @@ -7,6 +7,7 @@ package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -16,9 +17,9 @@ import org.mage.test.serverside.base.CardTestPlayerBase; */ public class ProwlTest extends CardTestPlayerBase { + @Ignore // have not figured out how to have the test API cast a card using Prowl yet @Test - public void testBasicProwlCasting() { - + public void testBasicProwlCasting() { // Auntie's Snitch {2}{B} Creature — Goblin Rogue (3/1) // 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.) @@ -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 * 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 public void testProwlWithCostDiscount() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/GratuitousViolenceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/GratuitousViolenceTest.java new file mode 100644 index 0000000000..e6f75563c8 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/GratuitousViolenceTest.java @@ -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); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java new file mode 100644 index 0000000000..7d53061032 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java @@ -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(); + } + +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java new file mode 100644 index 0000000000..c4cfce4e97 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java @@ -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(); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceHasSubtypeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceHasSubtypeCondition.java index d5347f072c..3d246b2417 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceHasSubtypeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceHasSubtypeCondition.java @@ -1,5 +1,6 @@ package mage.abilities.condition.common; +import java.util.List; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.game.Game; @@ -11,17 +12,21 @@ import mage.game.permanent.Permanent; */ public class SourceHasSubtypeCondition implements Condition { - private final String subtype; - - public SourceHasSubtypeCondition(String subtype) { - this.subtype = subtype; + private final List subtypes; + + public SourceHasSubtypeCondition(List subtypes) { + this.subtypes = subtypes; } - + @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { - return permanent.hasSubtype(subtype, game); + for (String subtype : subtypes) { + if (permanent.hasSubtype(subtype, game)) { + return true; + } + } } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java index 6e2ef7102a..269a1b347b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java @@ -30,9 +30,11 @@ package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; @@ -44,10 +46,19 @@ import mage.util.CardUtil; public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect { protected int amount; - + protected boolean putToGraveyard; + public LookLibraryTopCardTargetPlayerEffect(int amount) { super(Outcome.Benefit); this.amount = amount; + this.putToGraveyard = false; + setText(); + } + + public LookLibraryTopCardTargetPlayerEffect(int amount, boolean putToGraveyard) { + super(Outcome.Benefit); + this.amount = amount; + this.putToGraveyard = putToGraveyard; setText(); } @@ -58,6 +69,7 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect { public LookLibraryTopCardTargetPlayerEffect(final LookLibraryTopCardTargetPlayerEffect effect) { super(effect); amount = effect.amount; + putToGraveyard = effect.putToGraveyard; } @Override @@ -74,21 +86,38 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect { Cards cards = new CardsImpl(); cards.addAll(targetPlayer.getLibrary().getTopCards(game, amount)); 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 false; } - + private void setText() { - StringBuilder sb = new StringBuilder("look at the top "); + StringBuilder sb = new StringBuilder("look at the top "); if (amount > 1) { sb.append(CardUtil.numberToText(amount)); sb.append(" cards "); - } - else { + } else { sb.append(" card "); } 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(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ShuffleIntoLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ShuffleIntoLibraryTargetEffect.java new file mode 100644 index 0000000000..263991d020 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ShuffleIntoLibraryTargetEffect.java @@ -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"; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/ActivateAbilitiesAnyTimeYouCouldCastInstantEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/ActivateAbilitiesAnyTimeYouCouldCastInstantEffect.java new file mode 100644 index 0000000000..2123247071 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/ActivateAbilitiesAnyTimeYouCouldCastInstantEffect.java @@ -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 + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/AbilitiesCostReductionControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/AbilitiesCostReductionControllerEffect.java new file mode 100644 index 0000000000..c16fa33e36 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/AbilitiesCostReductionControllerEffect.java @@ -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); + } +} diff --git a/Mage/src/main/java/mage/cards/Card.java b/Mage/src/main/java/mage/cards/Card.java index 8d39c817c3..3befec124b 100644 --- a/Mage/src/main/java/mage/cards/Card.java +++ b/Mage/src/main/java/mage/cards/Card.java @@ -65,6 +65,8 @@ public interface Card extends MageObject { String getExpansionSetCode(); String getTokenSetCode(); + + String getTokenDescriptor(); void checkForCountersToAdd(Permanent permanent, Game game); diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 69a3c9265b..050e5d5ee0 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -74,6 +74,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { protected String cardNumber; public String expansionSetCode; protected String tokenSetCode; + protected String tokenDescriptor; protected Rarity rarity; protected boolean canTransform; protected Card secondSideCard; @@ -316,6 +317,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public String getTokenSetCode() { return tokenSetCode; } + + @Override + public String getTokenDescriptor() { + return tokenDescriptor; + } @Override public List getMana() { diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index 6697ce4239..595da012e2 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -86,6 +86,7 @@ public class PermanentToken extends PermanentImpl { this.toughness.modifyBaseValue(token.getToughness().getBaseValueModified()); this.supertype = token.getSupertype(); this.subtype = token.getSubtype(game); + this.tokenDescriptor = token.getTokenDescriptor(); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/Token.java b/Mage/src/main/java/mage/game/permanent/token/Token.java index 91e719ce57..f399a8af70 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Token.java @@ -55,6 +55,7 @@ public class Token extends MageObjectImpl { private int tokenType; private String originalCardNumber; private String originalExpansionSetCode; + private String tokenDescriptor; private boolean expansionSetCodeChecked; 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.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() { return description; @@ -241,13 +262,14 @@ public class Token extends MageObjectImpl { public void setOriginalCardNumber(String originalCardNumber) { this.originalCardNumber = originalCardNumber; } - - public String getOriginalExpansionSetCode() { + + public String getOriginalExpansionSetCode() { return originalExpansionSetCode; } public void setOriginalExpansionSetCode(String originalExpansionSetCode) { this.originalExpansionSetCode = originalExpansionSetCode; + setTokenDescriptor(); } public Card getCopySourceCard() { @@ -264,15 +286,20 @@ public class Token extends MageObjectImpl { if (availableImageSetCodes.size() > 0) { if (availableImageSetCodes.contains(code)) { setOriginalExpansionSetCode(code); - } else // we should not set random set if appropriate set is already used - if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty() - || !availableImageSetCodes.contains(getOriginalExpansionSetCode())) { - setOriginalExpansionSetCode(availableImageSetCodes.get(new Random().nextInt(availableImageSetCodes.size()))); + } else { + // we should not set random set if appropriate set is already used + if (getOriginalExpansionSetCode() == null || getOriginalExpansionSetCode().isEmpty() + || !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) { if (setCode == null || setCode.isEmpty()) { diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 537e86fbb3..fac945694d 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -572,6 +572,11 @@ public class Spell extends StackObjImpl implements Card { public String getTokenSetCode() { return card.getTokenSetCode(); } + + @Override + public String getTokenDescriptor() { + return card.getTokenDescriptor(); + } @Override public void setFaceDown(boolean value, Game game) { diff --git a/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java b/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java index f42ba28297..2883f3e1e1 100644 --- a/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetControlledCreaturePermanent.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.target.common; import mage.filter.common.FilterControlledCreaturePermanent; @@ -44,6 +43,10 @@ public class TargetControlledCreaturePermanent extends TargetControlledPermanent this(numTargets, numTargets, new FilterControlledCreaturePermanent(), false); } + public TargetControlledCreaturePermanent(int minNumTargets, int maxNumTargets) { + this(minNumTargets, maxNumTargets, new FilterControlledCreaturePermanent(), false); + } + public TargetControlledCreaturePermanent(FilterControlledCreaturePermanent filter) { super(1, 1, filter, false); }